Merge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb

* master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb:
  V4L/DVB (4712): Fix warning when compiling on x86_i64
  V4L/DVB (4711): Radio: No need to return void
  V4L/DVB (4708): Add tveeprom support for Philips FM1236/FM1216ME MK5
  V4L/DVB (4707): 4linux: complete conversion to hotplug safe PCI API
  V4L/DVB (4706): Do not enable VIDEO_V4L2 unconditionally
  V4L/DVB (4704): SAA713x: fixed compile warning in SECAM fixup
  V4L/DVB (4703): Add support for the ASUS EUROPA2 OEM board
  V4L/DVB (4702): Fix: set antenna input for DVB-T for Asus P7131 Dual hybrid
  V4L/DVB (4701): Saa713x audio fixes
  V4L/DVB (4676a): Remove Kconfig item for DiB7000M support
diff --git a/CREDITS b/CREDITS
index dba3e63..5329ead 100644
--- a/CREDITS
+++ b/CREDITS
@@ -2240,6 +2240,12 @@
 S: Freiburg
 S: Germany
 
+N: Paul E. McKenney
+E: paulmck@us.ibm.com
+W: http://www.rdrop.com/users/paulmck/
+D: RCU and variants
+D: rcutorture module
+
 N: Mike McLagan
 E: mike.mclagan@linux.org
 W: http://www.invlogic.com/~mmclagan
@@ -2981,6 +2987,10 @@
 S: 75013 Paris
 S: France
 
+N: Dipankar Sarma
+E: dipankar@in.ibm.com
+D: RCU
+
 N: Hannu Savolainen
 E: hannu@opensound.com
 D: Maintainer of the sound drivers until 2.1.x days.
@@ -3293,6 +3303,12 @@
 S: MacGregor A.C.T 2615
 S: Australia
 
+N: Josh Triplett
+E: josh@freedesktop.org
+P: 1024D/D0FE7AFB B24A 65C9 1D71 2AC2 DE87  CA26 189B 9946 D0FE 7AFB
+D: rcutorture maintainer
+D: lock annotations, finding and fixing lock bugs
+
 N: Winfried Trümper
 E: winni@xpilot.org
 W: http://www.shop.de/~winni/
@@ -3562,11 +3578,11 @@
 S: USA
 
 N: Steven Whitehouse
-E: SteveW@ACM.org
+E: steve@chygwyn.com
 W: http://www.chygwyn.com/~steve
-D: Linux DECnet project: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html
+D: Linux DECnet project
 D: Minor debugging of other networking protocols.
-D: Misc bug fixes and filesystem development
+D: Misc bug fixes and GFS2 filesystem development
 
 N: Hans-Joachim Widmaier
 E: hjw@zvw.de
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index 49c7457..2b5ac60 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -158,6 +158,7 @@
 !Emm/filemap.c
 !Emm/memory.c
 !Emm/vmalloc.c
+!Imm/page_alloc.c
 !Emm/mempool.c
 !Emm/page-writeback.c
 !Emm/truncate.c
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index c684abf..07a6355 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -14,7 +14,7 @@
   </authorgroup>
 
   <copyright>
-   <year>2003-2005</year>
+   <year>2003-2006</year>
    <holder>Jeff Garzik</holder>
   </copyright>
 
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 1d50cf0..f4dffad 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -221,3 +221,41 @@
 	disable irq on a given acquisition of that lock will result in
 	deadlock as soon as the RCU callback happens to interrupt that
 	acquisition's critical section.
+
+13.	SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu())
+	may only be invoked from process context.  Unlike other forms of
+	RCU, it -is- permissible to block in an SRCU read-side critical
+	section (demarked by srcu_read_lock() and srcu_read_unlock()),
+	hence the "SRCU": "sleepable RCU".  Please note that if you
+	don't need to sleep in read-side critical sections, you should
+	be using RCU rather than SRCU, because RCU is almost always
+	faster and easier to use than is SRCU.
+
+	Also unlike other forms of RCU, explicit initialization
+	and cleanup is required via init_srcu_struct() and
+	cleanup_srcu_struct().	These are passed a "struct srcu_struct"
+	that defines the scope of a given SRCU domain.	Once initialized,
+	the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
+	and synchronize_srcu().  A given synchronize_srcu() waits only
+	for SRCU read-side critical sections governed by srcu_read_lock()
+	and srcu_read_unlock() calls that have been passd the same
+	srcu_struct.  This property is what makes sleeping read-side
+	critical sections tolerable -- a given subsystem delays only
+	its own updates, not those of other subsystems using SRCU.
+	Therefore, SRCU is less prone to OOM the system than RCU would
+	be if RCU's read-side critical sections were permitted to
+	sleep.
+
+	The ability to sleep in read-side critical sections does not
+	come for free.	First, corresponding srcu_read_lock() and
+	srcu_read_unlock() calls must be passed the same srcu_struct.
+	Second, grace-period-detection overhead is amortized only
+	over those updates sharing a given srcu_struct, rather than
+	being globally amortized as they are for other forms of RCU.
+	Therefore, SRCU should be used in preference to rw_semaphore
+	only in extremely read-intensive situations, or in situations
+	requiring SRCU's read-side deadlock immunity or low read-side
+	realtime latency.
+
+	Note that, rcu_assign_pointer() and rcu_dereference() relate to
+	SRCU just as they do to other forms of RCU.
diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt
index 02e27bf..f84407c 100644
--- a/Documentation/RCU/rcu.txt
+++ b/Documentation/RCU/rcu.txt
@@ -45,7 +45,8 @@
 
 	Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
 	"rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
-	"synchronize_rcu", and "synchronize_net".
+	"srcu_read_lock", "srcu_read_unlock", "synchronize_rcu",
+	"synchronize_net", and "synchronize_srcu".
 
 o	What guidelines should I follow when writing code that uses RCU?
 
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index a494859..25a3c3f 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -28,6 +28,15 @@
 		To properly exercise RCU implementations with preemptible
 		read-side critical sections.
 
+nfakewriters	This is the number of RCU fake writer threads to run.  Fake
+		writer threads repeatedly use the synchronous "wait for
+		current readers" function of the interface selected by
+		torture_type, with a delay between calls to allow for various
+		different numbers of writers running in parallel.
+		nfakewriters defaults to 4, which provides enough parallelism
+		to trigger special cases caused by multiple writers, such as
+		the synchronize_srcu() early return optimization.
+
 stat_interval	The number of seconds between output of torture
 		statistics (via printk()).  Regardless of the interval,
 		statistics are printed when the module is unloaded.
@@ -44,9 +53,12 @@
 		a kernel that disables the scheduling-clock interrupt to
 		idle CPUs.  Boolean parameter, "1" to test, "0" otherwise.
 
-torture_type	The type of RCU to test: "rcu" for the rcu_read_lock()
-		API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu"
-		for the "srcu_read_lock()" API.
+torture_type	The type of RCU to test: "rcu" for the rcu_read_lock() API,
+		"rcu_sync" for rcu_read_lock() with synchronous reclamation,
+		"rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for
+		rcu_read_lock_bh() with synchronous reclamation, "srcu" for
+		the "srcu_read_lock()" API, and "sched" for the use of
+		preempt_disable() together with synchronize_sched().
 
 verbose		Enable debug printk()s.  Default is disabled.
 
@@ -118,6 +130,21 @@
 	as it is only incremented if a torture structure's counter
 	somehow gets incremented farther than it should.
 
+Different implementations of RCU can provide implementation-specific
+additional information.  For example, SRCU provides the following:
+
+	srcu-torture: rtc: f8cf46a8 ver: 355 tfle: 0 rta: 356 rtaf: 0 rtf: 346 rtmbe: 0
+	srcu-torture: Reader Pipe:  559738 939 0 0 0 0 0 0 0 0 0
+	srcu-torture: Reader Batch:  560434 243 0 0 0 0 0 0 0 0
+	srcu-torture: Free-Block Circulation:  355 354 353 352 351 350 349 348 347 346 0
+	srcu-torture: per-CPU(idx=1): 0(0,1) 1(0,1) 2(0,0) 3(0,1)
+
+The first four lines are similar to those for RCU.  The last line shows
+the per-CPU counter state.  The numbers in parentheses are the values
+of the "old" and "current" counters for the corresponding CPU.  The
+"idx" value maps the "old" and "current" values to the underlying array,
+and is useful for debugging.
+
 
 USAGE
 
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 820fee2..e0d6d99 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -778,6 +778,8 @@
 	rcu_read_unlock
 	rcu_read_lock_bh
 	rcu_read_unlock_bh
+	srcu_read_lock
+	srcu_read_unlock
 
 RCU pointer/list traversal:
 
@@ -804,6 +806,7 @@
 	synchronize_net
 	synchronize_sched
 	synchronize_rcu
+	synchronize_srcu
 	call_rcu
 	call_rcu_bh
 
diff --git a/Documentation/ecryptfs.txt b/Documentation/ecryptfs.txt
new file mode 100644
index 0000000..01d8a08
--- /dev/null
+++ b/Documentation/ecryptfs.txt
@@ -0,0 +1,77 @@
+eCryptfs: A stacked cryptographic filesystem for Linux
+
+eCryptfs is free software. Please see the file COPYING for details.
+For documentation, please see the files in the doc/ subdirectory.  For
+building and installation instructions please see the INSTALL file.
+
+Maintainer: Phillip Hellewell
+Lead developer: Michael A. Halcrow <mhalcrow@us.ibm.com>
+Developers: Michael C. Thompson
+            Kent Yoder
+Web Site: http://ecryptfs.sf.net
+
+This software is currently undergoing development. Make sure to
+maintain a backup copy of any data you write into eCryptfs.
+
+eCryptfs requires the userspace tools downloadable from the
+SourceForge site:
+
+http://sourceforge.net/projects/ecryptfs/
+
+Userspace requirements include:
+ - David Howells' userspace keyring headers and libraries (version
+   1.0 or higher), obtainable from
+   http://people.redhat.com/~dhowells/keyutils/
+ - Libgcrypt
+
+
+NOTES
+
+In the beta/experimental releases of eCryptfs, when you upgrade
+eCryptfs, you should copy the files to an unencrypted location and
+then copy the files back into the new eCryptfs mount to migrate the
+files.
+
+
+MOUNT-WIDE PASSPHRASE
+
+Create a new directory into which eCryptfs will write its encrypted
+files (i.e., /root/crypt).  Then, create the mount point directory
+(i.e., /mnt/crypt).  Now it's time to mount eCryptfs:
+
+mount -t ecryptfs /root/crypt /mnt/crypt
+
+You should be prompted for a passphrase and a salt (the salt may be
+blank).
+
+Try writing a new file:
+
+echo "Hello, World" > /mnt/crypt/hello.txt
+
+The operation will complete.  Notice that there is a new file in
+/root/crypt that is at least 12288 bytes in size (depending on your
+host page size).  This is the encrypted underlying file for what you
+just wrote.  To test reading, from start to finish, you need to clear
+the user session keyring:
+
+keyctl clear @u
+
+Then umount /mnt/crypt and mount again per the instructions given
+above.
+
+cat /mnt/crypt/hello.txt
+
+
+NOTES
+
+eCryptfs version 0.1 should only be mounted on (1) empty directories
+or (2) directories containing files only created by eCryptfs. If you
+mount a directory that has pre-existing files not created by eCryptfs,
+then behavior is undefined. Do not run eCryptfs in higher verbosity
+levels unless you are doing so for the sole purpose of debugging or
+development, since secret values will be written out to the system log
+in that case.
+
+
+Mike Halcrow
+mhalcrow@us.ibm.com
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 42b95e0..24f3c63 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -29,14 +29,6 @@
 
 ---------------------------
 
-What:	drivers that were depending on OBSOLETE_OSS_DRIVER
-        (config options already removed)
-When:	before 2.6.19
-Why:	OSS drivers with ALSA replacements
-Who:	Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
 What:	raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
 When:	November 2006
 Why:	Deprecated in favour of the new ioctl-based rawiso interface, which is
diff --git a/Documentation/filesystems/gfs2.txt b/Documentation/filesystems/gfs2.txt
new file mode 100644
index 0000000..593004b
--- /dev/null
+++ b/Documentation/filesystems/gfs2.txt
@@ -0,0 +1,43 @@
+Global File System
+------------------
+
+http://sources.redhat.com/cluster/
+
+GFS is a cluster file system. It allows a cluster of computers to
+simultaneously use a block device that is shared between them (with FC,
+iSCSI, NBD, etc).  GFS reads and writes to the block device like a local
+file system, but also uses a lock module to allow the computers coordinate
+their I/O so file system consistency is maintained.  One of the nifty
+features of GFS is perfect consistency -- changes made to the file system
+on one machine show up immediately on all other machines in the cluster.
+
+GFS uses interchangable inter-node locking mechanisms.  Different lock
+modules can plug into GFS and each file system selects the appropriate
+lock module at mount time.  Lock modules include:
+
+  lock_nolock -- allows gfs to be used as a local file system
+
+  lock_dlm -- uses a distributed lock manager (dlm) for inter-node locking
+  The dlm is found at linux/fs/dlm/
+
+In addition to interfacing with an external locking manager, a gfs lock
+module is responsible for interacting with external cluster management
+systems.  Lock_dlm depends on user space cluster management systems found
+at the URL above.
+
+To use gfs as a local file system, no external clustering systems are
+needed, simply:
+
+  $ mkfs -t gfs2 -p lock_nolock -j 1 /dev/block_device
+  $ mount -t gfs2 /dev/block_device /dir
+
+GFS2 is not on-disk compatible with previous versions of GFS.
+
+The following man pages can be found at the URL above:
+  gfs2_fsck	to repair a filesystem
+  gfs2_grow	to expand a filesystem online
+  gfs2_jadd	to add journals to a filesystem online
+  gfs2_tool	to manipulate, examine and tune a filesystem
+  gfs2_quota	to examine and change quota values in a filesystem
+  mount.gfs2	to help mount(8) mount a filesystem
+  mkfs.gfs2	to make a filesystem
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index 7f34778d..125093c 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -1,7 +1,7 @@
 Introduction
 ------------
 
-The configuration database is collection of configuration options
+The configuration database is a collection of configuration options
 organized in a tree structure:
 
 	+- Code maturity level options
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index e2cbd59..50f4edd 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -390,7 +390,7 @@
 	The kernel may be built with several different versions of
 	$(CC), each supporting a unique set of features and options.
 	kbuild provide basic support to check for valid options for $(CC).
-	$(CC) is useally the gcc compiler, but other alternatives are
+	$(CC) is usually the gcc compiler, but other alternatives are
 	available.
 
     as-option
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 12b3b24..ff571f9 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -289,9 +289,6 @@
 
 	autotest	[IA64]
 
-	awe=		[HW,OSS] AWE32/SB32/AWE64 wave table synth
-			Format: <io>,<memsize>,<isapnp>
-
 	aztcd=		[HW,CD] Aztech CD268 CDROM driver
 			Format: <io>,0x79 (?)
 
@@ -536,10 +533,6 @@
 			Default value is 0.
 			Value can be changed at runtime via /selinux/enforce.
 
-	es1370=		[HW,OSS]
-			Format: <lineout>[,<micbias>]
-			See also header of sound/oss/es1370.c.
-
 	es1371=		[HW,OSS]
 			Format: <spdif>,[<nomix>,[<amplifier>]]
 			See also header of sound/oss/es1371.c.
@@ -580,9 +573,6 @@
 	gscd=		[HW,CD]
 			Format: <io>
 
-	gus=		[HW,OSS]
-			Format: <io>,<irq>,<dma>,<dma16>
-
 	gvp11=		[HW,SCSI]
 
 	hashdist=	[KNL,NUMA] Large hashes allocated during boot
@@ -841,12 +831,6 @@
 			(machvec) in a generic kernel.
 			Example: machvec=hpzx1_swiotlb
 
-	mad16=		[HW,OSS] Format:
-			<io>,<irq>,<dma>,<dma16>,<mpu_io>,<mpu_irq>,<joystick>
-
-	maui=		[HW,OSS]
-			Format: <io>,<irq>
-
 	max_loop=	[LOOP] Maximum number of loopback devices that can
 			be mounted
 			Format: <1-256>
@@ -1114,9 +1098,6 @@
 	opl3=		[HW,OSS]
 			Format: <io>
 
-	opl3sa=		[HW,OSS]
-			Format: <io>,<irq>,<dma>,<dma2>,<mpu_io>,<mpu_irq>
-
 	opl3sa2=	[HW,OSS] Format:
 			<io>,<irq>,<dma>,<dma2>,<mss_io>,<mpu_io>,<ymode>,<loopback>[,<isapnp>,<multiple]
 
@@ -1357,10 +1338,6 @@
 	rcu.qlowmark=	[KNL,BOOT] Set threshold of queued
 			RCU callbacks below which batch limiting is re-enabled.
 
-	rcu.rsinterval=	[KNL,BOOT,SMP] Set the number of additional
-			RCU callbacks to queued before forcing reschedule
-			on all cpus.
-
 	rdinit=		[KNL]
 			Format: <full_path>
 			Run specified binary instead of /init from the ramdisk,
@@ -1455,9 +1432,6 @@
 
 	sg_def_reserved_size=	[SCSI]
 
-	sgalaxy=	[HW,OSS]
-			Format: <io>,<irq>,<dma>,<dma2>,<sgbase>
-
 	shapers=	[NET]
 			Maximal number of shapers.
 
@@ -1598,9 +1572,6 @@
 
 	snd-ymfpci=	[HW,ALSA]
 
-	sonicvibes=	[HW,OSS]
-			Format: <reverb>
-
 	sonycd535=	[HW,CD]
 			Format: <io>[,<irq>]
 
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 1ccc8a5..27b457c 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1440,6 +1440,258 @@
                descriptor-types-mask = <012b0ebf>;
        };
 
+   h) Board Control and Status (BCSR)
+
+   Required properties:
+
+    - device_type : Should be "board-control"
+    - reg : Offset and length of the register set for the device
+
+    Example:
+
+	bcsr@f8000000 {
+		device_type = "board-control";
+		reg = <f8000000 8000>;
+	};
+
+   i) Freescale QUICC Engine module (QE)
+   This represents qe module that is installed on PowerQUICC II Pro.
+   Hopefully it will merge backward compatibility with CPM/CPM2.
+   Basically, it is a bus of devices, that could act more or less
+   as a complete entity (UCC, USB etc ). All of them should be siblings on
+   the "root" qe node, using the common properties from there.
+   The description below applies to the the qe of MPC8360 and
+   more nodes and properties would be extended in the future.
+
+   i) Root QE device
+
+   Required properties:
+   - device_type : should be "qe";
+   - model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
+   - reg : offset and length of the device registers.
+   - bus-frequency : the clock frequency for QUICC Engine.
+
+   Recommended properties
+   - brg-frequency : the internal clock source frequency for baud-rate
+     generators in Hz.
+
+   Example:
+	qe@e0100000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "qe";
+		model = "QE";
+		ranges = <0 e0100000 00100000>;
+		reg = <e0100000 480>;
+		brg-frequency = <0>;
+		bus-frequency = <179A7B00>;
+	}
+
+
+   ii) SPI (Serial Peripheral Interface)
+
+   Required properties:
+   - device_type : should be "spi".
+   - compatible : should be "fsl_spi".
+   - mode : the spi operation mode, it can be "cpu" or "qe".
+   - reg : Offset and length of the register set for the device
+   - interrupts : <a b> where a is the interrupt number and b is a
+     field that represents an encoding of the sense and level
+     information for the interrupt.  This should be encoded based on
+     the information in section 2) depending on the type of interrupt
+     controller you have.
+   - interrupt-parent : the phandle for the interrupt controller that
+     services interrupts for this device.
+
+   Example:
+	spi@4c0 {
+		device_type = "spi";
+		compatible = "fsl_spi";
+		reg = <4c0 40>;
+		interrupts = <82 0>;
+		interrupt-parent = <700>;
+		mode = "cpu";
+	};
+
+
+   iii) USB (Universal Serial Bus Controller)
+
+   Required properties:
+   - device_type : should be "usb".
+   - compatible : could be "qe_udc" or "fhci-hcd".
+   - mode : the could be "host" or "slave".
+   - reg : Offset and length of the register set for the device
+   - interrupts : <a b> where a is the interrupt number and b is a
+     field that represents an encoding of the sense and level
+     information for the interrupt.  This should be encoded based on
+     the information in section 2) depending on the type of interrupt
+     controller you have.
+   - interrupt-parent : the phandle for the interrupt controller that
+     services interrupts for this device.
+
+   Example(slave):
+	usb@6c0 {
+		device_type = "usb";
+		compatible = "qe_udc";
+		reg = <6c0 40>;
+		interrupts = <8b 0>;
+		interrupt-parent = <700>;
+		mode = "slave";
+	};
+
+
+   iv) UCC (Unified Communications Controllers)
+
+   Required properties:
+   - device_type : should be "network", "hldc", "uart", "transparent"
+    "bisync" or "atm".
+   - compatible : could be "ucc_geth" or "fsl_atm" and so on.
+   - model : should be "UCC".
+   - device-id : the ucc number(1-8), corresponding to UCCx in UM.
+   - reg : Offset and length of the register set for the device
+   - interrupts : <a b> where a is the interrupt number and b is a
+     field that represents an encoding of the sense and level
+     information for the interrupt.  This should be encoded based on
+     the information in section 2) depending on the type of interrupt
+     controller you have.
+   - interrupt-parent : the phandle for the interrupt controller that
+     services interrupts for this device.
+   - pio-handle : The phandle for the Parallel I/O port configuration.
+   - rx-clock : represents the UCC receive clock source.
+     0x00 : clock source is disabled;
+     0x1~0x10 : clock source is BRG1~BRG16 respectively;
+     0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+   - tx-clock: represents the UCC transmit clock source;
+     0x00 : clock source is disabled;
+     0x1~0x10 : clock source is BRG1~BRG16 respectively;
+     0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+
+   Required properties for network device_type:
+   - mac-address : list of bytes representing the ethernet address.
+   - phy-handle : The phandle for the PHY connected to this controller.
+
+   Example:
+	ucc@2000 {
+		device_type = "network";
+		compatible = "ucc_geth";
+		model = "UCC";
+		device-id = <1>;
+		reg = <2000 200>;
+		interrupts = <a0 0>;
+		interrupt-parent = <700>;
+		mac-address = [ 00 04 9f 00 23 23 ];
+		rx-clock = "none";
+		tx-clock = "clk9";
+		phy-handle = <212000>;
+		pio-handle = <140001>;
+	};
+
+
+   v) Parallel I/O Ports
+
+   This node configures Parallel I/O ports for CPUs with QE support.
+   The node should reside in the "soc" node of the tree.  For each
+   device that using parallel I/O ports, a child node should be created.
+   See the definition of the Pin configuration nodes below for more
+   information.
+
+   Required properties:
+   - device_type : should be "par_io".
+   - reg : offset to the register set and its length.
+   - num-ports : number of Parallel I/O ports
+
+   Example:
+	par_io@1400 {
+		reg = <1400 100>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		device_type = "par_io";
+		num-ports = <7>;
+		ucc_pin@01 {
+			......
+		};
+
+
+   vi) Pin configuration nodes
+
+   Required properties:
+   - linux,phandle : phandle of this node; likely referenced by a QE
+     device.
+   - pio-map : array of pin configurations.  Each pin is defined by 6
+     integers.  The six numbers are respectively: port, pin, dir,
+     open_drain, assignment, has_irq.
+     - port : port number of the pin; 0-6 represent port A-G in UM.
+     - pin : pin number in the port.
+     - dir : direction of the pin, should encode as follows:
+
+	0 = The pin is disabled
+	1 = The pin is an output
+	2 = The pin is an input
+	3 = The pin is I/O
+
+     - open_drain : indicates the pin is normal or wired-OR:
+
+	0 = The pin is actively driven as an output
+	1 = The pin is an open-drain driver. As an output, the pin is
+	    driven active-low, otherwise it is three-stated.
+
+     - assignment : function number of the pin according to the Pin Assignment
+       tables in User Manual.  Each pin can have up to 4 possible functions in
+       QE and two options for CPM.
+     - has_irq : indicates if the pin is used as source of exteral
+       interrupts.
+
+   Example:
+	ucc_pin@01 {
+		linux,phandle = <140001>;
+		pio-map = <
+		/* port  pin  dir  open_drain  assignment  has_irq */
+			0  3  1  0  1  0 	/* TxD0 */
+			0  4  1  0  1  0 	/* TxD1 */
+			0  5  1  0  1  0 	/* TxD2 */
+			0  6  1  0  1  0 	/* TxD3 */
+			1  6  1  0  3  0 	/* TxD4 */
+			1  7  1  0  1  0 	/* TxD5 */
+			1  9  1  0  2  0 	/* TxD6 */
+			1  a  1  0  2  0 	/* TxD7 */
+			0  9  2  0  1  0 	/* RxD0 */
+			0  a  2  0  1  0 	/* RxD1 */
+			0  b  2  0  1  0 	/* RxD2 */
+			0  c  2  0  1  0 	/* RxD3 */
+			0  d  2  0  1  0 	/* RxD4 */
+			1  1  2  0  2  0 	/* RxD5 */
+			1  0  2  0  2  0 	/* RxD6 */
+			1  4  2  0  2  0 	/* RxD7 */
+			0  7  1  0  1  0 	/* TX_EN */
+			0  8  1  0  1  0 	/* TX_ER */
+			0  f  2  0  1  0 	/* RX_DV */
+			0  10 2  0  1  0 	/* RX_ER */
+			0  0  2  0  1  0 	/* RX_CLK */
+			2  9  1  0  3  0 	/* GTX_CLK - CLK10 */
+			2  8  2  0  1  0>;	/* GTX125 - CLK9 */
+	};
+
+   vii) Multi-User RAM (MURAM)
+
+   Required properties:
+   - device_type : should be "muram".
+   - mode : the could be "host" or "slave".
+   - ranges : Should be defined as specified in 1) to describe the
+      translation of MURAM addresses.
+   - data-only : sub-node which defines the address area under MURAM
+      bus that can be allocated as data/parameter
+
+   Example:
+
+	muram@10000 {
+		device_type = "muram";
+		ranges = <0 00010000 0000c000>;
+
+		data-only@0{
+			reg = <0 c000>;
+		};
+	};
 
    More devices will be defined as this spec matures.
 
diff --git a/Documentation/sound/oss/AWE32 b/Documentation/sound/oss/AWE32
deleted file mode 100644
index b5908a6..0000000
--- a/Documentation/sound/oss/AWE32
+++ /dev/null
@@ -1,76 +0,0 @@
-	Installing and using Creative AWE midi sound under Linux.
-
-This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and 
-SB32.
-
-1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This
-   is important, because the driver works only with real Creative cards.
-
-2) The first thing you need to do is re-compile your kernel with support for
-   your sound card. Run your favourite tool to configure the kernel and when
-   you get to the "Sound" menu you should enable support for the following:
-
-   Sound card support,
-   OSS sound modules,
-   100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support,
-   AWE32 synth
-
-   If your card is "Plug and Play" you will also need to enable these two
-   options, found under the "Plug and Play configuration" menu:
-
-   Plug and Play support
-   ISA Plug and Play support
-
-   Now compile and install the kernel in normal fashion. If you don't know
-   how to do this you can find instructions for this in the README file
-   located in the root directory of the kernel source.
-
-3) Before you can start playing midi files you will have to load a sound
-   bank file. The utility needed for doing this is called "sfxload", and it
-   is one of the utilities found in a package called "awesfx". If this
-   package is not available in your distribution you can download the AWE
-   snapshot from Creative Labs Open Source website:
-
-   http://www.opensource.creative.com/snapshot.html
-
-   Once you have unpacked the AWE snapshot you will see a "awesfx"
-   directory. Follow the instructions in awesfx/docs/INSTALL to install the
-   utilities in this package. After doing this, sfxload should be installed
-   as:
-
-   /usr/local/bin/sfxload
-
-   To enable AWE general midi synthesis you should also get the sound bank
-   file for general midi from:
-
-   http://members.xoom.com/yar/synthgm.sbk.gz
-
-   Copy it to a directory of your choice, and unpack it there.
-
-4) Edit /etc/modprobe.conf, and insert the following lines at the end of the
-   file:
-
-  alias sound-slot-0 sb
-  alias sound-service-0-1 awe_wave
-  install awe_wave /sbin/modprobe --first-time -i awe_wave && /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
-
-  You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
-  path of the sound bank file. That will enable the Sound Blaster and AWE
-  wave synthesis. To play midi files you should get one of these programs if
-  you don't already have them:
-
-  Playmidi:			http://playmidi.openprojects.net
-
-  AWEMidi Player (drvmidi)  	Included in the previously mentioned AWE
-  				snapshot.
-
-  You will probably have to pass the "-e" switch to playmidi to have it use
-  your midi device. drvmidi should work without switches.
-
-  If something goes wrong please e-mail me. All comments and suggestions are
-  welcome.
-
-		    Yaroslav Rosomakho (alons55@dialup.ptt.ru)
-			    http://www.yar.opennet.ru
-
-Last Updated: Feb 3 2001
diff --git a/Documentation/sound/oss/CMI8338 b/Documentation/sound/oss/CMI8338
deleted file mode 100644
index 387d058..0000000
--- a/Documentation/sound/oss/CMI8338
+++ /dev/null
@@ -1,85 +0,0 @@
-Audio driver for CM8338/CM8738 chips by Chen-Li Tien
-
-
-HARDWARE SUPPORTED
-================================================================================
-C-Media CMI8338
-C-Media CMI8738
-On-board C-Media chips
-
-
-STEPS TO BUILD DRIVER
-================================================================================
-
-  1. Backup the Config.in and Makefile in the sound driver directory
-     (/usr/src/linux/driver/sound).
-     The Configure.help provide help when you config driver in step
-     4, please backup the original one (/usr/src/linux/Document) and
-     copy this file.
-     The cmpci is document for the driver in detail, please copy it
-     to /usr/src/linux/Document/sound so you can refer it. Backup if
-     there is already one.
-
-  2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above
-     directory.
-
-  3. Change directory to /usr/src/linux
-
-  4. Config cm8338 driver by 'make menuconfig', 'make config' or
-     'make xconfig' command.
-
-  5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI
-     driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
-     For driver option, please refer 'DRIVER PARAMETER'
-
-  6. Compile the kernel if necessary.
-
-  7. Compile the modules by 'make modules'.
-
-  8. Install the modules by 'make modules_install'
-
-
-INSTALL DRIVER
-================================================================================
-
-  1. Before first time to run the driver, create module dependency by
-     'depmod -a'
-
-  2. To install the driver manually, enter 'modprobe cmpci'.
-
-  3. Driver installation for various distributions:
-
-    a. Slackware 4.0
-       Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules
-       file.so you can start the driver automatically each time booting.
-
-    b. Caldera OpenLinux 2.2
-       Use LISA to load the cmpci module.
-
-    c. RedHat 6.0 and S.u.S.E. 6.1
-       Add following command in /etc/conf.modules:
-
-       alias sound cmpci
-
-	also visit http://www.cmedia.com.tw for installation instruction.
-
-DRIVER PARAMETER
-================================================================================
-
-  Some functions for the cm8738 can be configured in Kernel Configuration
-  or modules parameters. Set these parameters to 1 to enable.
-
-  mpuio:	I/O ports base for MPU-401, 0 if disabled.
-  fmio:		I/O ports base for OPL-3, 0 if disabled.
-  spdif_inverse:Inverse the S/PDIF-in signal, this depends on your
-		CD-ROM or DVD-ROM.
-  spdif_loop:   Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
-                directly.
-  speakers:     Number of speakers used.
-  use_line_as_rear:Enable this if you want to use line-in as
-                rear-out.
-  use_line_as_bass:Enable this if you want to use line-in as
-                bass-out.
-  joystick:	Enable joystick. You will need to install Linux joystick
-		driver.
-
diff --git a/Documentation/sound/oss/INSTALL.awe b/Documentation/sound/oss/INSTALL.awe
deleted file mode 100644
index 310f42c..0000000
--- a/Documentation/sound/oss/INSTALL.awe
+++ /dev/null
@@ -1,134 +0,0 @@
-================================================================
-	INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX
-	Takashi Iwai	<iwai@ww.uni-erlangen.de>
-================================================================
-
-----------------------------------------------------------------
-* Attention to SB-PnP Card Users
-
-If you're using PnP cards, the initialization of PnP is required
-before loading this driver.  You have now three options:
-  1. Use isapnptools.
-  2. Use in-kernel isapnp support.
-  3. Initialize PnP on DOS/Windows, then boot linux by loadlin.
-In this document, only the case 1 case is treated.
-
-----------------------------------------------------------------
-* Installation on Red Hat 5.0 Sound Driver
-
-Please use install-rh.sh under RedHat5.0 directory.
-DO NOT USE install.sh below.
-See INSTALL.RH for more details.
-
-----------------------------------------------------------------
-* Installation/Update by Shell Script
-
-  1. Become root
-
-	% su
-
-  2. If you have never configured the kernel tree yet, run make config
-    once (to make dependencies and symlinks).
-
-	# cd /usr/src/linux
-	# make xconfig
-    
-  3. Run install.sh script
-
-	# sh ./install.sh
-
-  4. Configure your kernel
-
-	(for Linux 2.[01].x user)
-	# cd /usr/src/linux
-	# make xconfig (or make menuconfig)
-
-	(for Linux 1.2.x user)
-	# cd /usr/src/linux
-	# make config
-
-    Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items 
-    in Sound menu.  ("lowlevel drivers" will appear only in 2.x
-    kernel.)
-
-  5. Make your kernel (and modules), and install them as usual.
-
-	5a. make kernel image
-		# make zImage
-
-	5b. make modules and install them
-		# make modules && make modules_install
-
-	5c. If you're using lilo, copy the kernel image and run lilo.
-	    Otherwise, copy the kernel image to suitable directory or
-	    media for your system.
-
-  6. Reboot the kernel if necessary.
-	- If you updated only the modules, you don't have to reboot
-	  the system.  Just remove the old sound modules here.
-		in 
-		# rmmod sound.o		(linux-2.0 or OSS/Free)
-		# rmmod awe_wave.o	(linux-2.1)
-
-  7. If your AWE card is a PnP and not initialized yet, you'll have to
-    do it by isapnp tools.  Otherwise, skip to 8.
-
-	This section described only a brief explanation.  For more
-	details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ.
-
-	7a. If you have no isapnp.conf file, generate it by pnpdump.
-	    Otherwise, skip to 7d.
-		# pnpdump > /etc/isapnp.conf
-
-	7b. Edit isapnp.conf file.  Comment out the appropriate
-	    lines containing desirable I/O ports, DMA and IRQs.
-	    Don't forget to enable (ACT Y) line.
-
-	7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part.
-	    ex)
-		(CONFIGURE CTL0048/58128 (LD 2
-		#     ANSI string -->WaveTable<--
-		  (IO 0 (BASE 0x0620))
-		  (IO 1 (BASE 0x0A20))
-		  (IO 2 (BASE 0x0E20))
-		  (ACT Y)
-		))
-
-	7d. Load the config file.
-	    CAUTION: This will reset all PnP cards!
-
-		# isapnp /etc/isapnp.conf
-
-  8. Load the sound module (if you configured it as a module):
-
-	for 2.0 kernel or OSS/Free monolithic module:
-
-		# modprobe sound.o
-
-	for 2.1 kernel:
-
-		# modprobe sound
-		# insmod uart401
-		# insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
-		(These values depend on your settings.)
-		# insmod awe_wave
-		(Be sure to load awe_wave after sb!)
-
-		See Documentation/sound/oss/AWE32 for
-		more details.
-
-  9. (only for obsolete systems) If you don't have /dev/sequencer
-     device file, make it according to Readme.linux file on
-     /usr/src/linux/drivers/sound. (Run a shell script included in
-     that file). <-- This file no longer exists in the recent kernels!
-
-  10. OK, load your own soundfont file, and enjoy MIDI!
-
-	% sfxload synthgm.sbk
-	% drvmidi foo.mid
-
-  11. For more advanced use (eg. dynamic loading, virtual bank and
-      etc.), please read the awedrv FAQ or the instructions in awesfx
-      and awemidi packages.
-
-Good luck!
diff --git a/Documentation/sound/oss/MAD16 b/Documentation/sound/oss/MAD16
deleted file mode 100644
index 865dbd8..0000000
--- a/Documentation/sound/oss/MAD16
+++ /dev/null
@@ -1,56 +0,0 @@
-(This recipe has been edited to update the configuration symbols,
- and change over to modprobe.conf for 2.6)
-
-From: Shaw Carruthers <shaw@shawc.demon.co.uk>
-
-I have been using mad16 sound for some time now with no problems, current
-kernel 2.1.89
-
-lsmod shows:
-
-mad16                   5176   0 
-sb                     22044   0  [mad16]
-uart401                 5576   0  [mad16 sb]
-ad1848                 14176   1  [mad16]
-sound                  61928   0  [mad16 sb uart401 ad1848]
-
-.config has:
-
-CONFIG_SOUND=m
-CONFIG_SOUND_ADLIB=m
-CONFIG_SOUND_MAD16=m
-CONFIG_SOUND_YM3812=m
-
-modprobe.conf has:
-
-alias char-major-14-* mad16
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1  && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-
-To get the built in mixer to work this needs to be:
-
-options adlib_card io=0x388     # FM synthesizer
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is
-
-------------------------------------------------------------------------
-The mad16 module in addition supports the following options:
-
-option:			meaning:			default:
-joystick=0,1 		disabled, enabled 		disabled
-cdtype=0x00,0x02,0x04,	disabled, Sony CDU31A,		disabled
-       0x06,0x08,0x0a   Mitsumi, Panasonic,
-			Secondary IDE, Primary IDE 
-cdport=0x340,0x320,					0x340
-       0x330,0x360
-cdirq=0,3,5,7,9,10,11 	disabled, IRQ3, ... 		disabled
-cddma=0,5,6,7 		disabled, DMA5, ... 		DMA5 for Mitsumi or IDE
-cddma=0,1,2,3 		disabled, DMA1, ... 		DMA3 for Sony or Panasonic
-opl4=0,1 		OPL3, OPL4 			OPL3	
-
-for more details see linux/drivers/sound/mad16.c
-
-Rui Sousa
diff --git a/Documentation/sound/oss/Maestro b/Documentation/sound/oss/Maestro
deleted file mode 100644
index 4a80eb3..0000000
--- a/Documentation/sound/oss/Maestro
+++ /dev/null
@@ -1,123 +0,0 @@
-	An OSS/Lite Driver for the ESS Maestro family of sound cards
-
-			Zach Brown, December 1999
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
-	http://www.zabbo.net/maestro/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-ESS Maestro Chip Family
------------------------
-
-There are 3 main variants of the ESS Maestro PCI sound chip.  The first
-is the Maestro 1.  It was originally produced by Platform Tech as the
-'AGOGO'.  It can be recognized by Platform Tech's PCI ID 0x1285 with
-0x0100 as the device ID.  It was put on some sound boards and a few laptops.  
-ESS bought the design and cleaned it up as the Maestro 2.  This starts
-their marking with the ESS vendor ID 0x125D and the 'year' device IDs.
-The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978.
-
-The various families of Maestro are mostly identical as far as this 
-driver is concerned.  It doesn't touch the DSP parts that differ (though
-it could for FM synthesis).
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec.   This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves almost as expected.  Playback is
-supported in all the various lovely formats.  8/16bit stereo/mono from
-8khz to 48khz, and mmap()ing for playback behaves.  Capture/recording
-is limited due to oddities with the Maestro hardware.  One can only
-record in 16bit stereo.  For recording the maestro uses non interleaved
-stereo buffers so that mmap()ing the incoming data does not result in
-a ring buffer of LRLR data.  mmap()ing of the read buffers is therefore
-disallowed until this can be cleaned up.
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro.  It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro.  Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
-
-The driver doesn't support MIDI or FM playback at the moment.  Typically
-the Maestro is wired to an MPU MIDI chip, but some hardware implementations
-don't.  We need to assemble a white list of hardware implementations that
-have MIDI wired properly before we can claim to support it safely.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers.  Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO variable
-in the config system.  
-
-It may be modular or statically linked.  If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere.  'alias sound maestro'
-should also be added to your module configs (typically /etc/conf.modules)
-if you're using modular OSS/Lite sound and want to default to using a
-maestro chip.
-
-As this is a PCI device, the module does not need to be informed of
-any IO or IRQ resources it should use, it devines these from the
-system.  Sometimes, on sucky PCs, the BIOS fails to allocated resources
-for the maestro.  This will result in a message like:
-	maestro: PCI subsystem reports IRQ 0, this might not be correct.
-from the kernel.  Should this happen the sound chip most likely will
-not operate correctly.  To solve this one has to dig through their BIOS
-(typically entered by hitting a hot key at boot time) and figure out
-what magic needs to happen so that the BIOS will reward the maestro with
-an IRQ.  This operation is incredibly system specific, so you're on your
-own.  Sometimes the magic lies in 'PNP Capable Operating System' settings.
-
-There are very few options to the driver.  One is 'debug' which will 
-tell the driver to print minimal debugging information as it runs.  This
-can be collected with 'dmesg' or through the klogd daemon.
-
-The other, more interesting option, is 'dsps_order'.  Typically at
-install time the driver will only register one available /dev/dsp device
-for its use.  The 'dsps_order' module parameter allows for more devices
-to be allocated, as a power of two.  Up to 4 devices can be registered
-( dsps_order=2 ).  These devices act as fully distinct units and use
-separate channels in the maestro.
-
-Power Management
-----------------
-
-As of version 0.14, this driver has a minimal understanding of PCI
-Power Management.  If it finds a valid power management capability
-on the PCI device it will attempt to use the power management
-functions of the maestro.  It will only do this on Maestro 2Es and
-only on machines that are known to function well.  You can
-force the use of power management by setting the 'use_pm' module
-option to 1, or can disable it entirely by setting it to 0.
-
-When using power management, the driver does a few things
-differently.  It will keep the chip in a lower power mode
-when the module is inserted but /dev/dsp is not open.  This
-allows the mixer to function but turns off the clocks
-on other parts of the chip.  When /dev/dsp is opened the chip
-is brought into full power mode, and brought back down
-when it is closed.  It also powers down the chip entirely
-when the module is removed or the machine is shutdown.  This
-can have nonobvious consequences.  CD audio may not work
-after a power managing driver is removed.  Also, software that
-doesn't understand power management may not be able to talk
-to the powered down chip until the machine goes through a hard
-reboot to bring it back.
-
-.. more details ..
-------------------
-
-drivers/sound/maestro.c contains comments that hopefully explain
-the maestro implementation.
diff --git a/Documentation/sound/oss/Maestro3 b/Documentation/sound/oss/Maestro3
deleted file mode 100644
index a113718..0000000
--- a/Documentation/sound/oss/Maestro3
+++ /dev/null
@@ -1,92 +0,0 @@
-	An OSS/Lite Driver for the ESS Maestro3 family of sound chips
-
-			Zach Brown, January 2001
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
-	http://www.zabbo.net/maestro3/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-Historically I've sucked pretty hard at actually doing that, however.
-
-ESS Maestro3 Chip Family
------------------------
-
-The 'Maestro3' is much like the Maestro2 chip.  The noted improvement
-is the removal of the silicon in the '2' that did PCM mixing.  All that
-work is now done through a custom DSP called the ASSP, the Asynchronus
-Specific Signal Processor.
-
-The 'Allegro' is a baby version of the Maestro3.  I'm not entirely clear
-on the extent of the differences, but the driver supports them both :)
-
-The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
-both under ESS's vendor ID of 0x125D.  The Maestro3 can also show up as
-0x199a when hardware strapping is used.
-
-The chip can also act as a multi function device.  The modem IDs follow
-the audio multimedia device IDs.  (so the modem part of an Allegro shows
-up as 0x1989)
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec.   This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves as expected.  Playback is
-supported in all the various lovely formats.  8/16bit stereo/mono from
-8khz to 48khz, with both read()/write(), and mmap().
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro3.  It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro3.  Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer.  Not all AC'97s have them.
-The Allegro has an onchip AC'97.
-
-The driver doesn't support MIDI or FM playback at the moment.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers.  Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
-in the config system.  
-
-It may be modular or statically linked.  If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere.  'alias sound-slot-0
-maestro3' should also be added to your module configs (typically
-/etc/modprobe.conf) if you're using modular OSS/Lite sound and want to
-default to using a maestro3 chip.
-
-There are very few options to the driver.  One is 'debug' which will 
-tell the driver to print minimal debugging information as it runs.  This
-can be collected with 'dmesg' or through the klogd daemon.
-
-One is 'external_amp', which tells the driver to attempt to enable
-an external amplifier.  This defaults to '1', you can tell the driver
-not to bother enabling such an amplifier by setting it to '0'.
-
-And the last is 'gpio_pin', which tells the driver which GPIO pin number
-the external amp uses (0-15), The Allegro uses 8 by default, all others 1.
-If everything loads correctly and seems to be working but you get no sound, 
-try tweaking this value. 
-
-Systems known to need a different value
-        Panasonic ToughBook CF-72: gpio_pin=13 
-
-Power Management
-----------------
-
-This driver has a minimal understanding of PCI Power Management.  It will
-try and power down the chip when the system is suspended, and power
-it up with it is resumed.  It will also try and power down the chip
-when the machine is shut down.
diff --git a/Documentation/sound/oss/NEWS b/Documentation/sound/oss/NEWS
deleted file mode 100644
index a81e0ef..0000000
--- a/Documentation/sound/oss/NEWS
+++ /dev/null
@@ -1,42 +0,0 @@
-Linux 2.4 Sound Changes
-2000-September-25
-Christoph Hellwig, <hch@infradead.org>
-
-
-
-=== isapnp support
-
-The Linux 2.4 Kernel does have reliable in-kernel isapnp support.
-Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically
-detecting and configuring isapnp devices.
-If you have a not yet supported isapnp soundcard, mail me the content
-of '/proc/isapnp' on your system and some information about your card
-and its driver(s) so I can try to get isapnp working for it.
-
-
-
-=== soundcard resources on kernel commandline
-
-Before Linux 2.4 you had to specify the resources for sounddrivers
-statically linked into the kernel at compile time
-(in make config/menuconfig/xconfig). In Linux 2.4 the resources are
-now specified at the boot-time kernel commandline (e.g. the lilo
-'append=' line or everything that's after the kernel name in grub).
-Read the Configure.help entry for your card for the parameters.
-
-
-=== softoss is gone
-
-In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable.
-Use a user space software synthesizer like timidity instead.
-
-
-
-=== /dev/sndstat and /proc/sound are gone
-
-In older Linux versions those files exported some information about the
-OSS/Free configuration to userspace. In Linux 2.3 they were removed because
-they did not support the growing number of pci soundcards and there were
-some general problems with this interface.
-
-
diff --git a/Documentation/sound/oss/OPL3-SA b/Documentation/sound/oss/OPL3-SA
deleted file mode 100644
index 66a9183..0000000
--- a/Documentation/sound/oss/OPL3-SA
+++ /dev/null
@@ -1,52 +0,0 @@
-OPL3-SA1 sound driver (opl3sa.o)
-
----
-Note: This howto only describes how to setup the OPL3-SA1 chip; this info
-does not apply to the SA2, SA3, or SA4. 
----
-
-The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and
-it's a decent little chip offering a WSS mode, a SB Pro emulation mode, MPU401
-and OPL3 FM Synth capabilities.
-
-You can enable inclusion of the driver via CONFIG_SOUND_OPL3SA1=m, or
-CONFIG_SOUND_OPL3SA1=y through 'make config/xconfig/menuconfig'.
-
-You'll need to know all of the relevant info (irq, dma, and io port) for the
-chip's WSS mode, since that is the mode the kernel sound driver uses, and of
-course you'll also need to know about where the MPU401 and OPL3 ports and
-IRQs are if you want to use those.
-
-Here's the skinny on how to load it as a module:
-
-	modprobe opl3sa io=0x530 irq=11 dma=0 dma2=1 mpu_io=0x330 mpu_irq=5
-
-Module options in detail:
-
-	io:	This is the WSS's port base.
-	irq:	This is the WSS's IRQ.
-	dma:	This is the WSS's DMA line. In my BIOS setup screen this was
-		listed as "WSS Play DMA"
-	dma2:	This is the WSS's secondary DMA line. My BIOS calls it the
-		"WSS capture DMA"
-	
-	mpu_io:	This is the MPU401's port base.
-	mpu_irq: This is the MPU401's IRQ.
-
-If you'd like to use the OPL3 FM Synthesizer, make sure you enable
-CONFIG_SOUND_YM3812 (in 'make config'). That'll build the opl3.o module.
-
-Then a simple 'insmod opl3 io=0x388', and you now have FM Synth.
-
-You can also use the SoftOSS software synthesizer instead of the builtin OPL3.
-Here's how:
-
-Say 'y' or 'm' to "SoftOSS software wave table engine" in make config.
-
-If you said yes, the software synth is available once you boot your new
-kernel.
-
-If you chose to build it as a module, just insmod the resulting softoss2.o
-
-Questions? Comments?
-<stiker@northlink.com>
diff --git a/Documentation/sound/oss/README.awe b/Documentation/sound/oss/README.awe
deleted file mode 100644
index 80054cd..0000000
--- a/Documentation/sound/oss/README.awe
+++ /dev/null
@@ -1,218 +0,0 @@
-================================================================
-	AWE32 Sound Driver for Linux / FreeBSD
-		version 0.4.3; Nov. 1, 1998
-
-	Takashi Iwai <iwai@ww.uni-erlangen.de>
-================================================================
-
-* GENERAL NOTES
-
-This is a sound driver extension for SoundBlaster AWE32 and other
-compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable
-the wave synth operations.  The driver is provided for Linux 1.2.x
-and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC
-Alpha systems.
-
-This driver was written by Takashi Iwai <iwai@ww.uni-erlangen.de>,
-and provided "as is".  The original source (awedrv-0.4.3.tar.gz) and
-binary packages are available on the following URL:
-	http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/
-Note that since the author is apart from this web site, the update is
-not frequent now.
-
-
-* NOTE TO LINUX USERS
-
-To enable this driver on linux-2.[01].x kernels, you need turn on 
-"AWE32 synth" options in sound menu when configure your linux kernel
-and modules.  The precise installation procedure is described in the
-AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32.
-
-If you're using PnP cards, the card must be initialized before loading
-the sound driver.  There're several options to do this:
-    - Initialize the card via ISA PnP tools, and load the sound module.
-    - Initialize the card on DOS, and load linux by loadlin.exe
-    - Use PnP kernel driver (for Linux-2.x.x)
-The detailed instruction for the solution using isapnp tools is found
-in many documents like above.  A brief instruction is also included in
-the installation document of this package.
-For PnP driver project, please refer to the following URL:
-	http://www-jcr.lmh.ox.ac.uk/~pnp/
-
-
-* USING THE DRIVER
-
-The awedrv has several different playing modes to realize easy channel 
-allocation for MIDI songs.  To hear the exact sound quality, you need
-to obtain the extended sequencer program, drvmidi or playmidi-2.5.
-
-For playing MIDI files, you *MUST* load the soundfont file on the
-driver previously by sfxload utility.  Otherwise you'll here no sounds 
-at all!  All the utilities and driver source packages are found in the
-above URL.  The sfxload program is included in the package
-awesfx-0.4.3.tgz.  Binary packages are available there, too.  See the
-instruction in each package for installation.
-
-Loading a soundfont file is very simple.  Just execute the command
-
-	% sfxload synthgm.sbk
-
-Then, sfxload transfers the file "synthgm.sbk" to the driver.
-Both SF1 and SF2 formats are accepted.
-
-Now you can hear midi musics by a midi player.
-
-	% drvmidi foo.mid
-
-If you run MIDI player after MOD player, you need to load soundfont
-files again, since MOD player programs clear the previous loaded
-samples by their own data.
-
-If you have only 512kb on the sound card, I recommend to use dynamic
-sample loading via -L option of drvmidi.  2MB GM/GS soundfont file is
-available in most midi files.
-
-	% sfxload synthgm
-	% drvmidi -L 2mbgmgs foo.mid
-
-This makes a big difference (believe me)!  For more details, please
-refer to the FAQ list which is available on the URL above.
-
-The current chorus, reverb and equalizer status can be changed by
-aweset utility program (included in awesfx package).  Note that
-some awedrv-native programs (like drvmidi and xmp) will change the
-current settings by themselves.  The aweset program is effective
-only for other programs like playmidi.
-
-Enjoy.
-
-
-* COMPILE FLAGS
-
-Compile conditions are defined in awe_config.h.
-
-[Compatibility Conditions]
-The following flags are defined automatically when using installation
-shell script.
-
-- AWE_MODULE_SUPPORT
-    indicates your Linux kernel supports module for each sound card
-    (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels
-    as distributed in the RH5.0 package).
-    This flag is automatically set when you're using 2.1.x kernels.
-    You can pass the base address and memory size via the following
-    module options,
-	io = base I/O port address (eg. 0x620)
-	memsize = DRAM size in kilobytes (eg. 512)
-    As default, AWE driver probes these values automatically.
-
-
-[Hardware Conditions]
-You DON'T have to define the following two values.
-Define them only when the driver couldn't detect the card properly.
-
-- AWE_DEFAULT_BASE_ADDR		(default: not defined)
-    specifies the base port address of your AWE32 card.
-    0 means to autodetect the address.
-
-- AWE_DEFAULT_MEM_SIZE		(default: not defined)
-    specifies the memory size of your AWE32 card in kilobytes.
-    -1 means to autodetect its size.
-    
-
-[Sample Table Size]
-From ver.0.4.0, sample tables are allocated dynamically (except
-Linux-1.2.x system), so you need NOT to touch these parameters.
-Linux-1.2.x users may need to increase these values to appropriate size 
-if the sound card is equipped with more DRAM.
-
-- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS
-
-
-[Other Conditions]
-
-- AWE_ALWAYS_INIT_FM		(default: not defined)
-    indicates the AWE driver always initialize FM passthrough even
-    without DRAM on board.  Emu8000 chip has a restriction for playing
-    samples on DRAM that at least two channels must be occupied as
-    passthrough channels. 
-
-- AWE_DEBUG_ON			(default: defined)
-    turns on debugging messages if defined.
-
-- AWE_HAS_GUS_COMPATIBILITY	(default: defined)
-    Enables GUS compatibility mode if defined, reading GUS patches and 
-    GUS control commands.  Define this option to use GMOD or other
-    GUS module players.
-
-- CONFIG_AWE32_MIDIEMU		(default: defined)
-    Adds a MIDI emulation device by Emu8000 wavetable.  The emulation
-    device can be accessed as an external MIDI, and sends the MIDI
-    control codes directly.  XG and GS sysex/NRPN are accepted.
-    No MIDI input is supported.
-
-- CONFIG_AWE32_MIXER		(default: not defined)
-    Adds a mixer device for AWE32 bass/treble equalizer control.
-    You can access this device using /dev/mixer?? (usually mixer01).
-
-- AWE_USE_NEW_VOLUME_CALC	(default: defined)
-    Use the new method to calculate the volume change as compatible
-    with DOS/Win drivers.  This option can be toggled via aweset
-    program, or drvmidi player.
-
-- AWE_CHECK_VTARGET		(default: defined)
-    Check the current volume target value when searching for an
-    empty channel to allocate a new voice.  This is experimentally
-    implemented in this version.  (probably, this option doesn't
-    affect the sound quality severely...)
-
-- AWE_ALLOW_SAMPLE_SHARING	(default: defined)
-   Allow sample sharing for differently loaded patches.
-   This function is available only together with awesfx-0.4.3p3.
-   Note that this is still an experimental option.
-
-- DEF_FM_CHORUS_DEPTH		(default: 0x10)
-    The default strength to be sent to the chorus effect engine.
-    From 0 to 0xff.  Larger numbers may often cause weird sounds.
-
-- DEF_FM_REVERB_DEPTH		(default: 0x10)
-    The default strength to be sent to the reverb effect engine.
-    From 0 to 0xff.  Larger numbers may often cause weird sounds.
-
-
-* ACKNOWLEDGMENTS
-
-Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice
-on programming of AWE32.  Much code is brought from his AWE32-native 
-MOD player, ALMP.
-The port of awedrv to FreeBSD is done by Randall Hopper
-(rhh@ct.picker.com).
-The new volume calculation routine was derived from Mark Weaver's
-ADIP compatible routines.
-I also thank linux-awe-ml members for their efforts
-to reboot their system many times :-)
-
-
-* TODO'S
-
-- Complete DOS/Win compatibility
-- DSP-like output
-
-
-* COPYRIGHT
-
-Copyright (C) 1996-1998 Takashi Iwai
-
-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.
diff --git a/Documentation/sound/oss/Wavefront b/Documentation/sound/oss/Wavefront
deleted file mode 100644
index 16f57ea..0000000
--- a/Documentation/sound/oss/Wavefront
+++ /dev/null
@@ -1,339 +0,0 @@
-	     An OSS/Free Driver for WaveFront soundcards
-	       (Turtle Beach Maui, Tropez, Tropez Plus)
-
-		     Paul Barton-Davis, July 1998
-
-			  VERSION 0.2.5
-
-Driver Status
--------------
-
-Requires: Kernel 2.1.106 or later (the driver is included with kernels
-2.1.109 and above)
-	  
-As of 7/22/1998, this driver is currently in *BETA* state. This means
-that it compiles and runs, and that I use it on my system (Linux
-2.1.106) with some reasonably demanding applications and uses.  I
-believe the code is approaching an initial "finished" state that
-provides bug-free support for the Tropez Plus.
-
-Please note that to date, the driver has ONLY been tested on a Tropez
-Plus. I would very much like to hear (and help out) people with Tropez
-and Maui cards, since I think the driver can support those cards as
-well. 
-
-Finally, the driver has not been tested (or even compiled) as a static
-(non-modular) part of the kernel. Alan Cox's good work in modularizing
-OSS/Free for Linux makes this rather unnecessary.
-
-Some Questions
---------------
-
-**********************************************************************
-0) What does this driver do that the maui driver did not ?
-**********************************************************************
-
-* can fully initialize a WaveFront card from cold boot - no DOS 
-          utilities needed
-* working patch/sample/program loading and unloading (the maui
-      driver didn't document how to make this work, and assumed
-      user-level preparation of the patch data for writing
-      to the board. ick.)
-* full user-level access to all WaveFront commands
-* for the Tropez Plus, (primitive) control of the YSS225 FX processor
-* Virtual MIDI mode supported - 2 MIDI devices accessible via the
-          WaveFront's MPU401/UART emulation. One
-	  accesses the WaveFront synth, the other accesses the
-	  external MIDI connector. Full MIDI read/write semantics
-	  for both devices.
-* OSS-compliant /dev/sequencer interface for the WaveFront synth,
-	  including native and GUS-format patch downloading.
-* semi-intelligent patch management (prototypical at this point)
-
-**********************************************************************
-1) What to do about MIDI interfaces ?
-**********************************************************************
-
-The Tropez Plus (and perhaps other WF cards) can in theory support up
-to 2 physical MIDI interfaces. One of these is connected to the
-ICS2115 chip (the WaveFront synth itself) and is controlled by
-MPU/UART-401 emulation code running as part of the WaveFront OS.  The
-other is controlled by the CS4232 chip present on the board. However,
-physical access to the CS4232 connector is difficult, and it is
-unlikely (though not impossible) that you will want to use it.
-
-An older version of this driver introduced an additional kernel config
-variable which controlled whether or not the CS4232 MIDI interface was
-configured. Because of Alan Cox's work on modularizing the sound
-drivers, and now backporting them to 2.0.34 kernels, there seems to be
-little reason to support "static" configuration variables, and so this
-has been abandoned in favor of *only* module parameters. Specifying
-"mpuio" and "mpuirq" for the cs4232 parameter will result in the
-CS4232 MIDI interface being configured; leaving them unspecified will
-leave it unconfigured (and thus unusable).
-
-BTW, I have heard from one Tropez+ user that the CS4232 interface is
-more reliable than the ICS2115 one. I have had no problems with the
-latter, and I don't have the right cable to test the former one
-out. Reports welcome.
-
-**********************************************************************
-2) Why does line XXX of the code look like this .... ?
-**********************************************************************
-
-Either because it's not finished yet, or because you're a better coder
-than I am, or because you don't understand some aspect of how the card
-or the code works. 
-
-I absolutely welcome comments, criticisms and suggestions about the
-design and implementation of the driver. 
-
-**********************************************************************
-3) What files are included ?
-**********************************************************************
-
-   drivers/sound/README.wavefront       -- this file
-
-   drivers/sound/wavefront.patch	-- patches for the 2.1.106 sound drivers
-					   needed to make the rest of this work
-				           DO NOT USE IF YOU'VE APPLIED THEM 
-					   BEFORE, OR HAVE 2.1.109 OR ABOVE
-
-   drivers/sound/wavfront.c             -- the driver
-   drivers/sound/ys225.h                -- data declarations for FX config
-   drivers/sound/ys225.c                -- data definitions for FX config
-   drivers/sound/wf_midi.c              -- the "uart401" driver 
-   				              to support virtual MIDI mode.
-   include/wavefront.h                  -- the header file
-   Documentation/sound/oss/Tropez+          -- short docs on configuration
-
-**********************************************************************
-4) How do I compile/install/use it ?
-**********************************************************************
-
-PART ONE: install the source code into your sound driver directory
-
-  cd <top-of-your-2.1.106-code-base-e.g.-/usr/src/linux>
-  tar -zxvf <where-you-put/wavefront.tar.gz>
-
-PART TWO: apply the patches
-
-     DO THIS ONLY IF YOU HAVE A KERNEL VERSION BELOW 2.1.109
-     AND HAVE NOT ALREADY INSTALLED THE PATCH(ES).
-
-  cd drivers/sound
-  patch < wavefront.patch
-
-PART THREE: configure your kernel
-
-  cd <top of your kernel tree>
-  make xconfig (or whichever config option you use)
-
-         - choose YES for Sound Support	      
-         - choose MODULE (M) for OSS Sound Modules
-         - choose MODULE(M) to YM3812/OPL3 support
-	 - choose MODULE(M) for WaveFront support
-	 - choose MODULE(M) for CS4232 support
-
-	 - choose "N" for everything else (unless you have other
-	      soundcards you want support for)
-
-
-   make boot
-   .
-   .
-   .
-   <whatever you normally do for a kernel install>
-   make modules
-   .
-   .
-   .
-   make modules_install
-
-Here's my autoconf.h SOUND section:
-
-/*
- * Sound
- */
-#define CONFIG_SOUND 1
-#undef  CONFIG_SOUND_OSS
-#define CONFIG_SOUND_OSS_MODULE 1
-#undef  CONFIG_SOUND_PAS
-#undef  CONFIG_SOUND_SB
-#undef  CONFIG_SOUND_ADLIB
-#undef  CONFIG_SOUND_GUS
-#undef  CONFIG_SOUND_MPU401
-#undef  CONFIG_SOUND_PSS
-#undef  CONFIG_SOUND_MSS
-#undef  CONFIG_SOUND_SSCAPE
-#undef  CONFIG_SOUND_TRIX
-#undef  CONFIG_SOUND_MAD16
-#undef  CONFIG_SOUND_WAVEFRONT
-#define CONFIG_SOUND_WAVEFRONT_MODULE 1
-#undef  CONFIG_SOUND_CS4232
-#define CONFIG_SOUND_CS4232_MODULE 1
-#undef  CONFIG_SOUND_MAUI
-#undef  CONFIG_SOUND_SGALAXY
-#undef  CONFIG_SOUND_OPL3SA1
-#undef  CONFIG_SOUND_SOFTOSS
-#undef  CONFIG_SOUND_YM3812
-#define CONFIG_SOUND_YM3812_MODULE 1
-#undef  CONFIG_SOUND_VMIDI
-#undef  CONFIG_SOUND_UART6850
-/*
- * Additional low level sound drivers
- */
-#undef  CONFIG_LOWLEVEL_SOUND
-
-************************************************************
-6) How do I configure my card ?
-************************************************************
-
-You need to edit /etc/modprobe.conf. Here's mine (edited to show the
-relevant details):
-
-  # Sound system
-  alias char-major-14-* wavefront
-  alias synth0 wavefront
-  alias mixer0 cs4232
-  alias audio0 cs4232
-  install wavefront /sbin/modprobe cs4232 && /sbin/modprobe -i wavefront && /sbin/modprobe opl3
-  options wavefront io=0x200 irq=9
-  options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
-  options opl3 io=0x388
-
-Things to note: 
-
-       the wavefront options "io" and "irq" ***MUST*** match the "synthio"
-       and "synthirq" cs4232 options.
-
-       you can do without the opl3 module if you don't
-       want to use the OPL/[34] FM synth on the soundcard
-
-       the opl3 io parameter is conventionally not adjustable.
-       In theory, any not-in-use IO port address would work, but
-       just use 0x388 and stick with the crowd.
-
-**********************************************************************
-7) What about firmware ?
-**********************************************************************
-
-Turtle Beach have not given me permission to distribute their firmware
-for the ICS2115. However, if you have a WaveFront card, then you
-almost certainly have the firmware, and if not, its freely available
-on their website, at:
-
-   http://www.tbeach.com/tbs/downloads/scardsdown.htm#tropezplus 
-
-The file is called WFOS2001.MOT (for the Tropez+).
-
-This driver, however, doesn't use the pure firmware as distributed,
-but instead relies on a somewhat processed form of it. You can
-generate this very easily. Following an idea from Andrew Veliath's
-Pinnacle driver, the following flex program will generate the
-processed version:
-
----- cut here -------------------------
-%option main
-%%
-^S[28].*\r$ printf ("%c%.*s", yyleng-1,yyleng-1,yytext);
-<<EOF>> { fputc ('\0', stdout); return; }
-\n {} 
-.  {}
----- cut here -------------------------
-
-To use it, put the above in file (say, ws.l) compile it like this:
-
-      shell> flex -ows.c ws.l
-      shell> cc -o ws ws.c
-      
-and then use it like this:
-
-    ws < my-copy-of-the-oswf.mot-file > /etc/sound/wavefront.os
-
-If you put it somewhere else, you'll always have to use the wf_ospath
-module parameter (see below) or alter the source code.
-
-**********************************************************************
-7) How do I get it working ?
-**********************************************************************
-
-Optionally, you can reboot with the "new" kernel (even though the only
-changes have really been made to a module).
-
-Then, as root do:
-
-     modprobe wavefront
-
-You should get something like this in /var/log/messages:
-
-    WaveFront: firmware 1.20 already loaded.
-
-or 
-
-    WaveFront: no response to firmware probe, assume raw.
-
-then:
-
-    WaveFront: waiting for memory configuration ...
-    WaveFront: hardware version 1.64
-    WaveFront: available DRAM 8191k
-    WaveFront: 332 samples used (266 real, 13 aliases, 53 multi), 180 empty
-    WaveFront: 128 programs slots in use
-    WaveFront: 256 patch slots filled, 142 in use
-
-The whole process takes about 16 seconds, the longest waits being
-after reporting the hardware version (during the firmware download),
-and after reporting program status (during patch status inquiry).  Its
-shorter (about 10 secs) if the firmware is already loaded (i.e. only
-warm reboots since the last firmware load).
-
-The "available DRAM" line will vary depending on how much added RAM
-your card has. Mine has 8MB.
-
-To check basically functionality, use play(1) or splay(1) to send a
-.WAV or other audio file through the audio portion. Then use playmidi
-to play a General MIDI file. Try the "-D 0" to hear the
-difference between sending MIDI to the WaveFront and using the OPL/3,
-which is the default (I think ...). If you have an external synth(s)
-hooked to the soundcard, you can use "-e" to route to the
-external synth(s) (in theory, -D 1 should work as well, but I think
-there is a bug in playmidi which prevents this from doing what it
-should). 
-
-**********************************************************************
-8) What are the module parameters ?
-**********************************************************************
-
-Its best to read wavefront.c for this, but here is a summary:
-
-integers: 
-	  wf_raw  - if set, ignore apparent presence of firmware
-		    loaded onto the ICS2115, reset the whole
-		    board, and initialize it from scratch. (default = 0)
-
-          fx_raw  - if set, always initialize the YSS225 processor
-		    on the Tropez plus. (default = 1)
-
-          < The next 4 are basically for kernel hackers to allow
-	    tweaking the driver for testing purposes. >		    
-
-          wait_usecs        -  loop timer used when waiting for
-			       status conditions on the board. 
-			       The default is 150.
-
-          debug_default    - debugging flags. See sound/wavefront.h
-			     for WF_DEBUG_* values. Default is zero.
-			     Setting this allows you to debug the
-			     driver during module installation.
-strings:
-	  ospath - path to get to the pre-processed OS firmware.
-		    (default: /etc/sound/wavefront.os)
-
-**********************************************************************
-9) Who should I contact if I have problems?
-**********************************************************************
-
-Just me: Paul Barton-Davis <pbd@op.net>
-
-
diff --git a/Documentation/sound/oss/es1370 b/Documentation/sound/oss/es1370
deleted file mode 100644
index 7b38b1a..0000000
--- a/Documentation/sound/oss/es1370
+++ /dev/null
@@ -1,70 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-This soundcard does not have any hardware MIDI synthesizer;
-MIDI synthesis has to be done in software. To allow this
-the driver/soundcard supports two PCM (/dev/dsp) interfaces.
-The second one goes to the mixer "synth" setting and supports
-only a limited set of sampling rates (44100, 22050, 11025, 5512).
-By setting lineout to 1 on the driver command line
-(eg. insmod es1370 lineout=1) it is even possible on some
-cards to convert the LINEIN jack into a second LINEOUT jack, thus
-making it possible to output four independent audio channels!
-
-There is a freely available software package that allows
-MIDI file playback on this soundcard called Timidity.
-See http://www.cgs.fi/~tt/timidity/.
-
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/Documentation/sound/oss/rme96xx b/Documentation/sound/oss/rme96xx
deleted file mode 100644
index 87d7b7b..0000000
--- a/Documentation/sound/oss/rme96xx
+++ /dev/null
@@ -1,767 +0,0 @@
-Beta release of the rme96xx (driver for RME 96XX cards like the 
-"Hammerfall" and the "Hammerfall light") 
-
-Important: The driver module has to be installed on a freshly rebooted system, 
-otherwise the driver might not be able to acquire its buffers.
-
-features:
-
- - OSS programming interface (i.e. runs with standard OSS soundsoftware) 
- - OSS/Multichannel interface (OSS multichannel is done by just aquiring
-   more than 2 channels). The driver does not use more than one device 
-   ( yet .. this feature may be implemented later ) 
- - more than one RME card supported
-
-The driver uses a specific multichannel interface, which I will document
-when the driver gets stable. (take a look at the defines in rme96xx.h,
-which adds blocked multichannel formats i.e instead of 
-lrlrlrlr --> llllrrrr  etc.
-
-Use the "rmectrl" programm to look at the status of the card .. 
-or use xrmectrl, a GUI interface for the ctrl program.
-
-What you can do with the rmectrl program is to set the stereo device for
-OSS emulation (e.g. if you use SPDIF out).
-
-You do:
-
-./ctrl offset 24 24
-
-which makes the stereo device use channels 25 and 26.
-
-Guenter Geiger <geiger@epy.co.at>
-
-copy the first part of the attached source code into rmectrl.c
-and the  second part into xrmectrl (or get the program from
-http://gige.xdv.org/pages/soft/pages/rme)
-
-to compile: gcc -o rmectrl rmectrl.c
------------------------------- snip ------------------------------------
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <linux/soundcard.h>
-#include <math.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "rme96xx.h"
-
-/*
-  remctrl.c
-  (C) 2000 Guenter Geiger <geiger@debian.org>
-  HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-*/
-
-/* # define DEVICE_NAME "/dev/mixer" */
-# define DEVICE_NAME "/dev/mixer1"
-
-
-void usage(void)
-{
-     fprintf(stderr,"usage: rmectrl [/dev/mixer<n>] [command [options]]\n\n");
-     fprintf(stderr,"where command is one of:\n");
-     fprintf(stderr,"  help                       show this help\n");
-     fprintf(stderr,"  status                     show status bits\n");
-     fprintf(stderr,"  control                    show control bits\n");
-     fprintf(stderr,"  mix                        show mixer/offset status\n");
-     fprintf(stderr,"  master <n>                 set sync master\n");
-     fprintf(stderr,"  pro <n>                    set spdif out pro\n");
-     fprintf(stderr,"  emphasis <n>               set spdif out emphasis\n");
-     fprintf(stderr,"  dolby <n>                  set spdif out no audio\n");
-     fprintf(stderr,"  optout <n>                 set spdif out optical\n");
-     fprintf(stderr,"  wordclock <n>              set sync wordclock\n");
-     fprintf(stderr,"  spdifin <n>                set spdif in (0=optical,1=coax,2=intern)\n");
-     fprintf(stderr,"  syncref <n>                set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n");
-     fprintf(stderr,"  adat1cd <n>                set ADAT1 on internal CD\n");
-     fprintf(stderr,"  offset <devnr> <in> <out>  set dev (0..3) offset (0..25)\n");
-     exit(-1);
-}
-
-
-int main(int argc, char* argv[])
-{
-     int cards;
-     int ret;
-     int i;
-     double ft;
-     int fd, fdwr;
-     int param,orig;
-     rme_status_t stat;
-     rme_ctrl_t ctrl;
-     char *device;
-     int argidx;
-
-     if (argc < 2)
-	  usage();
-
-     if (*argv[1]=='/') {
-	  device = argv[1];
-	  argidx = 2;
-     }
-     else {
-	  device = DEVICE_NAME;
-	  argidx = 1;
-     }
-
-     fprintf(stdout,"mixer device %s\n",device);
-     if ((fd = open(device,O_RDONLY)) < 0) {
-	  fprintf(stdout,"opening device failed\n");
-	  exit(-1);
-     }
-
-     if ((fdwr = open(device,O_WRONLY)) < 0) {
-	  fprintf(stdout,"opening device failed\n");
-	  exit(-1);
-     }
-
-     if (argc < argidx+1)
-	  usage();
-
-     if (!strcmp(argv[argidx],"help"))
-        usage();
-     if (!strcmp(argv[argidx],"-h"))
-        usage();
-     if (!strcmp(argv[argidx],"--help"))
-        usage();
-
-     if (!strcmp(argv[argidx],"status")) {
-	  ioctl(fd,SOUND_MIXER_PRIVATE2,&stat);
-	  fprintf(stdout,"stat.irq %d\n",stat.irq);
-	  fprintf(stdout,"stat.lockmask %d\n",stat.lockmask);
-	  fprintf(stdout,"stat.sr48 %d\n",stat.sr48);
-	  fprintf(stdout,"stat.wclock %d\n",stat.wclock);
-	  fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint);
-	  fprintf(stdout,"stat.syncmask %d\n",stat.syncmask);
-	  fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed);
-	  fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy);
-	  fprintf(stdout,"stat.tc_out %d\n",stat.tc_out);
-	  fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate);
-	  fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error);
-	  fprintf(stdout,"stat.bufid %d\n",stat.bufid);
-	  fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"control")) {
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  fprintf(stdout,"ctrl.start %d\n",ctrl.start);
-	  fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency);
-	  fprintf(stdout,"ctrl.master %d\n",ctrl.master);
-	  fprintf(stdout,"ctrl.ie %d\n",ctrl.ie);
-	  fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48);
-	  fprintf(stdout,"ctrl.spare %d\n",ctrl.spare);
-	  fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed);
-	  fprintf(stdout,"ctrl.pro %d\n",ctrl.pro);
-	  fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis);
-	  fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby);
-	  fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out);
-	  fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock);
-	  fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in);
-	  fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref);
-	  fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset);
-	  fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select);
-	  fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock);
-	  fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write);
-	  fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"mix")) {
-	  rme_mixer mix;
-	  int i;
-
-	  for (i=0; i<4; i++) {
-	       mix.devnr = i;
-	       ioctl(fd,SOUND_MIXER_PRIVATE1,&mix);
-	       if (mix.devnr == i) {
-		    fprintf(stdout,"devnr %d\n",mix.devnr);
-		    fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset);
-		    fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset);
-	       }
-	  }
-	  exit (0);
-     }
-
-/* the control flags */
-
-     if (argc < argidx+2)
-	  usage();
-
-     if (!strcmp(argv[argidx],"master")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("master = %d\n",val);
-	  ctrl.master = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"pro")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("pro = %d\n",val);
-	  ctrl.pro = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"emphasis")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("emphasis = %d\n",val);
-	  ctrl.emphasis = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"dolby")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("dolby = %d\n",val);
-	  ctrl.dolby = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"optout")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("optout = %d\n",val);
-	  ctrl.opt_out = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"wordclock")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("wordclock = %d\n",val);
-	  ctrl.wordclock = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"spdifin")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("spdifin = %d\n",val);
-	  ctrl.spdif_in = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"syncref")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("syncref = %d\n",val);
-	  ctrl.sync_ref = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-     if (!strcmp(argv[argidx],"adat1cd")) {
-	  int val = atoi(argv[argidx+1]);
-	  ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
-	  printf("adat1cd = %d\n",val);
-	  ctrl.adat1_cd = val;
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
-	  exit (0);
-     }
-
-/* setting offset */
-
-     if (argc < argidx+4)
-	  usage();
-
-     if (!strcmp(argv[argidx],"offset")) {
-	  rme_mixer mix;
-
-	  mix.devnr = atoi(argv[argidx+1]);
-
-	  mix.i_offset = atoi(argv[argidx+2]);
-	  mix.o_offset = atoi(argv[argidx+3]);
-	  ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix);
-	  fprintf(stdout,"devnr %d\n",mix.devnr);
-	  fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset);
-	  fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset);
-	  exit (0);
-     }
-
-     usage();
-     exit (0); /* to avoid warning */
-}
-
-
----------------------------- <snip> --------------------------------
-#!/usr/bin/wish
-
-# xrmectrl
-# (C) 2000 Guenter Geiger <geiger@debian.org>
-# HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-
-#set defaults "-relief ridged"
-set CTRLPROG "./rmectrl"
-if {$argc} {
-    set CTRLPROG "$CTRLPROG $argv"
-}
-puts "CTRLPROG $CTRLPROG"
-
-frame .butts
-button .butts.exit -text "Exit" -command "exit" -relief ridge
-#button .butts.state -text "State" -command "get_all"
-
-pack .butts.exit -side left
-pack .butts -side bottom
-
-
-#
-# STATUS
-#
-
-frame .status
-
-# Sampling Rate
-
-frame .status.sr
-label .status.sr.text -text "Sampling Rate" -justify left
-radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times
-radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times
-radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times
-radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw  -variable srate -value 96000 -font times
-
-pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3
-
-# Lock
-
-frame .status.lock
-label .status.lock.text -text "Lock" -justify left
-checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times
-checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times
-checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times
-
-pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3 
-
-# Sync
-
-frame .status.sync
-label .status.sync.text -text "Sync" -justify left
-checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times
-checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times
-checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times
-
-pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3 
-
-# Timecode
-
-frame .status.tc
-label .status.tc.text -text "Timecode" -justify left
-checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times
-checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times
-checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times
-
-pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3 
-
-# SPDIF In
-
-frame .status.spdif
-label .status.spdif.text -text "SPDIF In" -justify left
-label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times
-checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times
-
-pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3 
-
-pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1
-
-
-#
-# CONTROL 
-#
-
-proc setprof {} {
-    global CTRLPROG
-    global spprof
-    exec $CTRLPROG pro $spprof
-}
-
-proc setemph {} {
-    global CTRLPROG
-    global spemph
-    exec $CTRLPROG emphasis $spemph
-}
-
-proc setnoaud {} {
-    global CTRLPROG
-    global spnoaud
-    exec $CTRLPROG dolby $spnoaud
-}
-
-proc setoptical {} {
-    global CTRLPROG
-    global spoptical
-    exec $CTRLPROG optout $spoptical
-}
-
-proc setspdifin {} {
-    global CTRLPROG
-    global spdifin
-    exec $CTRLPROG spdifin [expr $spdifin - 1]
-}
-
-proc setsyncsource {} {
-    global CTRLPROG
-    global syncsource
-    exec $CTRLPROG syncref [expr $syncsource -1]
-}
-
-
-proc setmaster {} {
-    global CTRLPROG
-    global master
-    exec $CTRLPROG master $master
-}
-
-proc setwordclock {} {
-    global CTRLPROG
-    global wordclock
-    exec $CTRLPROG wordclock $wordclock
-}
-
-proc setadat1cd {} {
-    global CTRLPROG
-    global adat1cd
-    exec $CTRLPROG adat1cd $adat1cd
-}
-
-
-frame .control
-
-# SPDIF In & SPDIF Out
-
-
-frame .control.spdif
-
-frame .control.spdif.in
-label .control.spdif.in.text -text "SPDIF In" -justify left
-radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times
-radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times
-radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times
-
-checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times
-
-pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd
-
-label .control.spdif.space
-
-frame .control.spdif.out
-label .control.spdif.out.text -text "SPDIF Out" -justify left
-checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times
-checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times
-checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times
-checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times
-
-pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom
-
-pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1
-
-# Sync Mode & Sync Source
-
-frame .control.sync
-frame .control.sync.mode
-label .control.sync.mode.text -text "Sync Mode" -justify left
-checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times
-checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times
-
-pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc
-
-label .control.sync.space
-
-frame .control.sync.src
-label .control.sync.src.text -text "Sync Source" -justify left
-radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times
-radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times
-radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times
-radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times
-
-pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom
-
-pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1
-
-label .control.space -text "" -width 10
-
-# Buffer Size
-
-frame .control.buf
-label .control.buf.text -text "Buffer Size (Latency)" -justify left
-radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times
-radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times
-radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times
-radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times
-radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times
-radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times
-radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times
-radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times
-
-pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3 
-
-# Offset
-
-frame .control.offset
-
-frame .control.offset.in
-label .control.offset.in.text -text "Offset In" -justify left
-label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
-label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
-label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
-label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
-
-pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3
-
-label .control.offset.space
-
-frame .control.offset.out
-label .control.offset.out.text -text "Offset Out" -justify left
-label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
-label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
-label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
-label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
-
-pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom
-
-pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1
-
-
-pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1
-
-
-label .statustext -text Status -justify center -relief ridge
-label .controltext -text Control -justify center -relief ridge
-
-label .statusspace
-label .controlspace
-
-pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1
-
-
-proc get_bit {output sstr} {
-    set idx1 [string last [concat $sstr 1] $output]
-    set idx1 [expr $idx1 != -1]
-    return $idx1
-}
-
-proc get_val {output sstr} {
-    set val [string wordend $output [string last $sstr $output]] 
-    set val [string range $output $val [expr $val+1]]
-    return $val
-}
-
-proc get_val2 {output sstr} {
-    set val [string wordend $output [string first $sstr $output]] 
-    set val [string range $output $val [expr $val+2]]
-    return $val
-}
-
-proc get_control {} {
-    global spprof
-    global spemph
-    global spnoaud
-    global spoptical
-    global spdifin
-    global ssrate
-    global master
-    global wordclock
-    global syncsource
-    global CTRLPROG
-
-    set f [open "| $CTRLPROG control" r+]
-    set ooo [read $f 1000]
-    close $f
-#    puts $ooo
-
-    set spprof [ get_bit $ooo "pro"]
-    set spemph [ get_bit $ooo "emphasis"]
-    set spnoaud [ get_bit $ooo "dolby"]
-    set spoptical [ get_bit $ooo "opt_out"]
-    set spdifin [ expr [ get_val $ooo "spdif_in"] + 1]
-    set ssrate [ expr [ get_val $ooo "latency"] + 1]
-    set master [ expr [ get_val $ooo "master"]]
-    set wordclock [ expr [ get_val $ooo "wordclock"]]
-    set syncsource [ expr [ get_val $ooo "sync_ref"] + 1]
-}
-
-proc get_status {} {
-    global srate
-    global ctrlcom
-
-    global adatlock1
-    global adatlock2
-    global adatlock3
-
-    global adatsync1
-    global adatsync2
-    global adatsync3
-
-    global tcbusy
-    global tcout
-    global tcvalid
-
-    global spdiferr
-    global crystal
-    global .status.spdif.text
-    global CTRLPROG
-
-
-    set f [open "| $CTRLPROG status" r+]
-    set ooo [read $f 1000]
-    close $f
-#    puts $ooo
-
-# samplerate
-
-    set idx1 [string last "sr48 1" $ooo]
-    set idx2 [string last "doublespeed 1" $ooo]
-    if {$idx1 >= 0} {
-	set fact1 48000
-    } else {
-	set fact1 44100
-    }
-
-    if {$idx2 >= 0} {
-	set fact2 2
-    } else {
-	set fact2 1
-    }
-    set srate [expr $fact1 * $fact2]
-#   ADAT lock
-
-    set val [get_val $ooo lockmask]
-    set adatlock1 0
-    set adatlock2 0
-    set adatlock3 0
-    if {[expr $val & 1]} {
-       set adatlock3 1
-    }
-    if {[expr $val & 2]} {
-       set adatlock2 1
-    }
-    if {[expr $val & 4]} {
-       set adatlock1 1
-    }
-
-#  ADAT sync
-    set val [get_val $ooo syncmask]
-    set adatsync1 0
-    set adatsync2 0
-    set adatsync3 0
-
-    if {[expr $val & 1]} {
-       set adatsync3 1
-    }
-    if {[expr $val & 2]} {
-       set adatsync2 1
-    }
-    if {[expr $val & 4]} {
-       set adatsync1 1
-    }
-
-# TC busy
-
-    set tcbusy [get_bit $ooo "busy"]
-    set tcout [get_bit $ooo "out"]
-    set tcvalid [get_bit $ooo "valid"]
-    set spdiferr [expr [get_bit $ooo "spdif_error"] == 0]
-
-#  000=64kHz, 100=88.2kHz, 011=96kHz
-#  111=32kHz, 110=44.1kHz, 101=48kHz
-
-    set val [get_val $ooo crystalrate]
-
-    set crystal "--.- kHz"
-    if {$val == 0} {
-        set crystal "64 kHz"
-    }
-    if {$val == 4} {
-        set crystal "88.2 kHz"
-    }
-    if {$val == 3} {
-        set crystal "96 kHz"
-    }
-    if {$val == 7} {
-        set crystal "32 kHz"
-    }
-    if {$val == 6} {
-        set crystal "44.1 kHz"
-    }
-    if {$val == 5} {
-        set crystal "48 kHz"
-    }
-    .status.spdif.sr configure -text $crystal
-}
-
-proc get_offset {} {
-    global inoffset
-    global outoffset
-    global CTRLPROG
-
-    set f [open "| $CTRLPROG mix" r+]
-    set ooo [read $f 1000]
-    close $f
-#    puts $ooo
-
-    if { [string match "*devnr*" $ooo] } {
-	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
-	set val [get_val2 $ooo i_offset]
-	.control.offset.in.off0 configure -text "dev\#0: $val"
-	set val [get_val2 $ooo o_offset]
-	.control.offset.out.off0 configure -text "dev\#0: $val"
-    } else {
-	.control.offset.in.off0 configure -text "dev\#0: -"
-	.control.offset.out.off0 configure -text "dev\#0: -"
-    }
-    if { [string match "*devnr*" $ooo] } {
-	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
-	set val [get_val2 $ooo i_offset]
-	.control.offset.in.off1 configure -text "dev\#1: $val"
-	set val [get_val2 $ooo o_offset]
-	.control.offset.out.off1 configure -text "dev\#1: $val"
-    } else {
-	.control.offset.in.off1 configure -text "dev\#1: -"
-	.control.offset.out.off1 configure -text "dev\#1: -"
-    }
-    if { [string match "*devnr*" $ooo] } {
-	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
-	set val [get_val2 $ooo i_offset]
-	.control.offset.in.off2 configure -text "dev\#2: $val"
-	set val [get_val2 $ooo o_offset]
-	.control.offset.out.off2 configure -text "dev\#2: $val"
-    } else {
-	.control.offset.in.off2 configure -text "dev\#2: -"
-	.control.offset.out.off2 configure -text "dev\#2: -"
-    }
-    if { [string match "*devnr*" $ooo] } {
-	set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
-	set val [get_val2 $ooo i_offset]
-	.control.offset.in.off3 configure -text "dev\#3: $val"
-	set val [get_val2 $ooo o_offset]
-	.control.offset.out.off3 configure -text "dev\#3: $val"
-    } else {
-	.control.offset.in.off3 configure -text "dev\#3: -"
-	.control.offset.out.off3 configure -text "dev\#3: -"
-    }
-}
-
-
-proc get_all {} {
-get_status
-get_control
-get_offset
-}
-
-# main
-while {1} {
-  after 200
-  get_all
-  update
-}
diff --git a/Documentation/sound/oss/solo1 b/Documentation/sound/oss/solo1
deleted file mode 100644
index 95c4c834..0000000
--- a/Documentation/sound/oss/solo1
+++ /dev/null
@@ -1,70 +0,0 @@
-Recording
----------
-
-Recording does not work on the author's card, but there
-is at least one report of it working on later silicon.
-The chip behaves differently than described in the data sheet,
-likely due to a chip bug. Working around this would require
-the help of ESS (for example by publishing an errata sheet),
-but ESS has not done so far.
-
-Also, the chip only supports 24 bit addresses for recording,
-which means it cannot work on some Alpha mainboards.
-
-
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (or later, available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card has an OPL compatible FM synthesizer.
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/Documentation/sound/oss/sonicvibes b/Documentation/sound/oss/sonicvibes
deleted file mode 100644
index 84dee2e..0000000
--- a/Documentation/sound/oss/sonicvibes
+++ /dev/null
@@ -1,81 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card both has an OPL compatible FM synthesizer as well as
-a wavetable synthesizer.
-
-I haven't managed so far to get the OPL synth running.
-
-Using the wavetable synthesizer requires allocating
-1-4MB of physically contiguous memory, which isn't possible
-currently on Linux without ugly hacks like the bigphysarea
-patch. Therefore, the driver doesn't support wavetable
-synthesis.
-
-
-No support from S3
-------------------
-
-I do not get any support from S3. Therefore, the driver
-still has many problems. For example, although the manual
-states that the chip should be able to access the sample
-buffer anywhere in 32bit address space, I haven't managed to
-get it working with buffers above 16M. Therefore, the card
-has the same disadvantages as ISA soundcards.
-
-Given that the card is also very noisy, and if you haven't
-already bought it, you should strongly opt for one of the
-comparatively priced Ensoniq products.
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/MAINTAINERS b/MAINTAINERS
index 1c6223d..17becb9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -898,6 +898,16 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+DISTRIBUTED LOCK MANAGER
+P:	Patrick Caulfield
+M:	pcaulfie@redhat.com
+P:	David Teigland
+M:	teigland@redhat.com
+L:	cluster-devel@redhat.com
+W:	http://sources.redhat.com/cluster/
+T:	git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git
+S:	Supported
+
 DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
 P:	Tobias Ringstrom
 M:	tori@unhappy.mine.nu
@@ -977,6 +987,13 @@
 W:	http://ebtables.sourceforge.net/
 S:	Maintained
 
+ECRYPT FILE SYSTEM
+P:	Mike Halcrow, Phillip Hellewell
+M:	mhalcrow@us.ibm.com, phillip@hellewell.homeip.net
+L:	ecryptfs-devel@lists.sourceforge.net
+W:	http://ecryptfs.sourceforge.net/
+S:	Supported
+
 EDAC-CORE
 P:	Doug Thompson
 M:	norsk5@xmission.com
@@ -1166,6 +1183,14 @@
 W:	http://www.kernel.org/pub/linux/utils/net/hdlc/
 S:	Maintained
 
+GFS2 FILE SYSTEM
+P:	Steven Whitehouse
+M:	swhiteho@redhat.com
+L:	cluster-devel@redhat.com
+W:	http://sources.redhat.com/cluster/
+T:	git kernel.org:/pub/scm/linux/kernel/git/steve/gfs-2.6.git
+S:	Supported
+
 GIGASET ISDN DRIVERS
 P:	Hansjoerg Lipp
 M:	hjlipp@web.de
@@ -1893,11 +1918,6 @@
 W: 	http://www.syskonnect.com
 S: 	Supported
 
-MAESTRO PCI SOUND DRIVERS
-P:	Zach Brown
-M:	zab@zabbo.net
-S:	Odd Fixes
-
 MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
 P: Michael Kerrisk
 M: mtk-manpages@gmx.net
@@ -2434,6 +2454,19 @@
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+READ-COPY UPDATE (RCU)
+P:	Dipankar Sarma
+M:	dipankar@in.ibm.com
+W:	http://www.rdrop.com/users/paulmck/rclock/
+L:	linux-kernel@vger.kernel.org
+S:	Supported
+
+RCUTORTURE MODULE
+P:	Josh Triplett
+M:	josh@freedesktop.org
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 REAL TIME CLOCK DRIVER
 P:	Paul Gortmaker
 M:	p_gortmaker@yahoo.com
@@ -2854,6 +2887,11 @@
 W:	http://tcp-lp-mod.sourceforge.net/
 S:	Maintained
 
+TI FLASH MEDIA INTERFACE DRIVER
+P:      Alex Dubov
+M:      oakad@yahoo.com
+S:      Maintained
+
 TI OMAP RANDOM NUMBER GENERATOR SUPPORT
 P:	Deepak Saxena
 M:	dsaxena@plexity.net
@@ -3377,12 +3415,6 @@
 L:	usbb2k-api-dev@nongnu.org
 S:	Maintained
 
-YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
-P:	Pete Zaitcev
-M:	zaitcev@yahoo.com
-L:	linux-kernel@vger.kernel.org
-S:	Obsolete
-
 Z8530 DRIVER FOR AX.25
 P:	Joerg Reuter
 M:	jreuter@yaina.de
diff --git a/Makefile b/Makefile
index 4c6c5e3..adb2c74 100644
--- a/Makefile
+++ b/Makefile
@@ -1321,7 +1321,7 @@
 		--langdef=kconfig \
 		--language-force=kconfig \
 		--regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \
-	    $(all-defconfigs) | xargs $1 -a \
+	    $(all-defconfigs) | xargs -r $1 -a \
 		--langdef=dotconfig \
 		--language-force=dotconfig \
 		--regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \
@@ -1329,7 +1329,7 @@
 	    $(all-sources) | xargs $1 -a; \
 	    $(all-kconfigs) | xargs $1 -a \
 		--regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \
-	    $(all-defconfigs) | xargs $1 -a \
+	    $(all-defconfigs) | xargs -r $1 -a \
 		--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
 	else \
 	    $(all-sources) | xargs $1 -a; \
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index fd4a8fa..a94e6d9 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -21,7 +21,6 @@
 #include <linux/a.out.h>
 #include <linux/screen_info.h>
 #include <linux/delay.h>
-#include <linux/config.h>	/* CONFIG_ALPHA_LCA etc */
 #include <linux/mc146818rtc.h>
 #include <linux/console.h>
 #include <linux/cpu.h>
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 4342cea..f6cfe8c 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -4,7 +4,6 @@
  * The system call table. 
  */
 
-#include <linux/config.h>			/* CONFIG_OSF4_COMPAT */
 #include <asm/unistd.h>
 
 	.data
diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig
index 4f3d8d3..c82e466 100644
--- a/arch/arm/configs/at91rm9200dk_defconfig
+++ b/arch/arm/configs/at91rm9200dk_defconfig
@@ -553,9 +553,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig
index 08b5dc3..b983fc5 100644
--- a/arch/arm/configs/at91rm9200ek_defconfig
+++ b/arch/arm/configs/at91rm9200ek_defconfig
@@ -534,9 +534,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/ateb9200_defconfig b/arch/arm/configs/ateb9200_defconfig
index bee7813..15e6b0b 100644
--- a/arch/arm/configs/ateb9200_defconfig
+++ b/arch/arm/configs/ateb9200_defconfig
@@ -656,9 +656,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/carmeva_defconfig b/arch/arm/configs/carmeva_defconfig
index 8a075c8..d24ae87 100644
--- a/arch/arm/configs/carmeva_defconfig
+++ b/arch/arm/configs/carmeva_defconfig
@@ -455,8 +455,8 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig
index cf3fa5c..a2d6fd3 100644
--- a/arch/arm/configs/csb337_defconfig
+++ b/arch/arm/configs/csb337_defconfig
@@ -591,9 +591,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig
index 640d70c..2a1ac6c 100644
--- a/arch/arm/configs/csb637_defconfig
+++ b/arch/arm/configs/csb637_defconfig
@@ -591,9 +591,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/kafa_defconfig b/arch/arm/configs/kafa_defconfig
index 1db633e..54fcd75 100644
--- a/arch/arm/configs/kafa_defconfig
+++ b/arch/arm/configs/kafa_defconfig
@@ -536,9 +536,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/kb9202_defconfig b/arch/arm/configs/kb9202_defconfig
index 45396e0..b4cd4b4 100644
--- a/arch/arm/configs/kb9202_defconfig
+++ b/arch/arm/configs/kb9202_defconfig
@@ -418,8 +418,8 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/onearm_defconfig b/arch/arm/configs/onearm_defconfig
index 6a93e3a..cb1d94f 100644
--- a/arch/arm/configs/onearm_defconfig
+++ b/arch/arm/configs/onearm_defconfig
@@ -583,9 +583,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
index 7481759..cec8378 100644
--- a/arch/arm/kernel/crunch.c
+++ b/arch/arm/kernel/crunch.c
@@ -10,7 +10,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff --git a/arch/arm/kernel/iwmmxt-notifier.c b/arch/arm/kernel/iwmmxt-notifier.c
index 44a86c3..0d1a1db 100644
--- a/arch/arm/kernel/iwmmxt-notifier.c
+++ b/arch/arm/kernel/iwmmxt-notifier.c
@@ -15,7 +15,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
diff --git a/arch/arm/mach-at91rm9200/board-1arm.c b/arch/arm/mach-at91rm9200/board-1arm.c
index 36eecd7..971c3e2 100644
--- a/arch/arm/mach-at91rm9200/board-1arm.c
+++ b/arch/arm/mach-at91rm9200/board-1arm.c
@@ -18,7 +18,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-at91rm9200/board-carmeva.c b/arch/arm/mach-at91rm9200/board-carmeva.c
index 50e5136..9820874 100644
--- a/arch/arm/mach-at91rm9200/board-carmeva.c
+++ b/arch/arm/mach-at91rm9200/board-carmeva.c
@@ -19,7 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-at91rm9200/board-eb9200.c b/arch/arm/mach-at91rm9200/board-eb9200.c
index c6e0d51..65e867b 100644
--- a/arch/arm/mach-at91rm9200/board-eb9200.c
+++ b/arch/arm/mach-at91rm9200/board-eb9200.c
@@ -19,7 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-at91rm9200/board-kafa.c b/arch/arm/mach-at91rm9200/board-kafa.c
index 91e3019..6ef3c48 100644
--- a/arch/arm/mach-at91rm9200/board-kafa.c
+++ b/arch/arm/mach-at91rm9200/board-kafa.c
@@ -18,7 +18,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-at91rm9200/board-kb9202.c b/arch/arm/mach-at91rm9200/board-kb9202.c
index 272fe43b..35a954a 100644
--- a/arch/arm/mach-at91rm9200/board-kb9202.c
+++ b/arch/arm/mach-at91rm9200/board-kb9202.c
@@ -19,7 +19,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c
index 0152553..0598243 100644
--- a/arch/arm/mach-at91rm9200/devices.c
+++ b/arch/arm/mach-at91rm9200/devices.c
@@ -544,7 +544,7 @@
  *  UART
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_SERIAL_AT91)
+#if defined(CONFIG_SERIAL_ATMEL)
 static struct resource dbgu_resources[] = {
 	[0] = {
 		.start	= AT91_VA_BASE_SYS + AT91_DBGU,
@@ -558,13 +558,14 @@
 	},
 };
 
-static struct at91_uart_data dbgu_data = {
+static struct atmel_uart_data dbgu_data = {
 	.use_dma_tx	= 0,
 	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
+	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
 };
 
 static struct platform_device at91rm9200_dbgu_device = {
-	.name		= "at91_usart",
+	.name		= "atmel_usart",
 	.id		= 0,
 	.dev		= {
 				.platform_data	= &dbgu_data,
@@ -593,13 +594,13 @@
 	},
 };
 
-static struct at91_uart_data uart0_data = {
+static struct atmel_uart_data uart0_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
 };
 
 static struct platform_device at91rm9200_uart0_device = {
-	.name		= "at91_usart",
+	.name		= "atmel_usart",
 	.id		= 1,
 	.dev		= {
 				.platform_data	= &uart0_data,
@@ -635,13 +636,13 @@
 	},
 };
 
-static struct at91_uart_data uart1_data = {
+static struct atmel_uart_data uart1_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
 };
 
 static struct platform_device at91rm9200_uart1_device = {
-	.name		= "at91_usart",
+	.name		= "atmel_usart",
 	.id		= 2,
 	.dev		= {
 				.platform_data	= &uart1_data,
@@ -676,13 +677,13 @@
 	},
 };
 
-static struct at91_uart_data uart2_data = {
+static struct atmel_uart_data uart2_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
 };
 
 static struct platform_device at91rm9200_uart2_device = {
-	.name		= "at91_usart",
+	.name		= "atmel_usart",
 	.id		= 3,
 	.dev		= {
 				.platform_data	= &uart2_data,
@@ -711,13 +712,13 @@
 	},
 };
 
-static struct at91_uart_data uart3_data = {
+static struct atmel_uart_data uart3_data = {
 	.use_dma_tx	= 1,
 	.use_dma_rx	= 1,
 };
 
 static struct platform_device at91rm9200_uart3_device = {
-	.name		= "at91_usart",
+	.name		= "atmel_usart",
 	.id		= 4,
 	.dev		= {
 				.platform_data	= &uart3_data,
@@ -733,8 +734,8 @@
 	at91_set_B_periph(AT91_PIN_PA6, 0);		/* RXD3 */
 }
 
-struct platform_device *at91_uarts[AT91_NR_UART];	/* the UARTs to use */
-struct platform_device *at91_default_console_device;	/* the serial console device */
+struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+struct platform_device *atmel_default_console_device;	/* the serial console device */
 
 void __init at91_init_serial(struct at91_uart_config *config)
 {
@@ -775,9 +776,9 @@
 	}
 
 	/* Set serial console device */
-	if (config->console_tty < AT91_NR_UART)
-		at91_default_console_device = at91_uarts[config->console_tty];
-	if (!at91_default_console_device)
+	if (config->console_tty < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[config->console_tty];
+	if (!atmel_default_console_device)
 		printk(KERN_INFO "AT91: No default serial console defined.\n");
 }
 
@@ -785,7 +786,7 @@
 {
 	int i;
 
-	for (i = 0; i < AT91_NR_UART; i++) {
+	for (i = 0; i < ATMEL_MAX_UART; i++) {
 		if (at91_uarts[i])
 			platform_device_register(at91_uarts[i]);
 	}
diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c
index 62a8efd..0315615 100644
--- a/arch/arm/mach-ep93xx/edb9302.c
+++ b/arch/arm/mach-ep93xx/edb9302.c
@@ -10,7 +10,6 @@
  * your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c
index 9e39921..e310e4d 100644
--- a/arch/arm/mach-ep93xx/edb9312.c
+++ b/arch/arm/mach-ep93xx/edb9312.c
@@ -11,7 +11,6 @@
  * your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
index ef7482f..249ca9e 100644
--- a/arch/arm/mach-ep93xx/edb9315.c
+++ b/arch/arm/mach-ep93xx/edb9315.c
@@ -10,7 +10,6 @@
  * your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c
index fa958e9..7ca0e61 100644
--- a/arch/arm/mach-ep93xx/edb9315a.c
+++ b/arch/arm/mach-ep93xx/edb9315a.c
@@ -10,7 +10,6 @@
  * your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/mm.h>
diff --git a/arch/arm/mach-lh7a40x/clcd.c b/arch/arm/mach-lh7a40x/clcd.c
index 93751fe..1992db4 100644
--- a/arch/arm/mach-lh7a40x/clcd.c
+++ b/arch/arm/mach-lh7a40x/clcd.c
@@ -8,7 +8,7 @@
  *  version 2 as published by the Free Software Foundation.
  *
  */
-#include <linux/config.h>
+
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
diff --git a/arch/arm/mach-lh7a40x/clocks.c b/arch/arm/mach-lh7a40x/clocks.c
index 2291afe9..7530a95 100644
--- a/arch/arm/mach-lh7a40x/clocks.c
+++ b/arch/arm/mach-lh7a40x/clocks.c
@@ -8,7 +8,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/cpufreq.h>
 #include <asm/hardware.h>
 #include <asm/arch/clocks.h>
diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c
index 5e20e74..2494091 100644
--- a/arch/arm/mach-omap2/pm-domain.c
+++ b/arch/arm/mach-omap2/pm-domain.c
@@ -15,7 +15,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/clk.h>
diff --git a/arch/arm/mach-pnx4008/gpio.c b/arch/arm/mach-pnx4008/gpio.c
index e1ce050..1ab84ce 100644
--- a/arch/arm/mach-pnx4008/gpio.c
+++ b/arch/arm/mach-pnx4008/gpio.c
@@ -14,7 +14,6 @@
  * or implied.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff --git a/arch/arm/mach-pnx4008/sleep.S b/arch/arm/mach-pnx4008/sleep.S
index 93c802b..fea1e17 100644
--- a/arch/arm/mach-pnx4008/sleep.S
+++ b/arch/arm/mach-pnx4008/sleep.S
@@ -11,7 +11,6 @@
  * or implied.
  */
 
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/hardware.h>
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 756228d..b986065 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -11,7 +11,6 @@
  * or implied.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
diff --git a/arch/arm/mach-pxa/leds-trizeps4.c b/arch/arm/mach-pxa/leds-trizeps4.c
index 14cfc85..2271d20 100644
--- a/arch/arm/mach-pxa/leds-trizeps4.c
+++ b/arch/arm/mach-pxa/leds-trizeps4.c
@@ -10,7 +10,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/init.h>
 
 #include <asm/hardware.h>
diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
index 2f9c9b5..ce319ef 100644
--- a/arch/arm/tools/gen-mach-types
+++ b/arch/arm/tools/gen-mach-types
@@ -28,7 +28,6 @@
 	  printf(" */\n\n");
 	  printf("#ifndef __ASM_ARM_MACH_TYPE_H\n");
 	  printf("#define __ASM_ARM_MACH_TYPE_H\n\n");
-	  printf("#include <linux/config.h>\n\n");
 	  printf("#ifndef __ASSEMBLY__\n");
 	  printf("/* The type of machine we're running on */\n");
 	  printf("extern unsigned int __machine_arch_type;\n");
diff --git a/arch/arm26/lib/ecard.S b/arch/arm26/lib/ecard.S
index b463315..658bc45 100644
--- a/arch/arm26/lib/ecard.S
+++ b/arch/arm26/lib/ecard.S
@@ -7,7 +7,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/config.h> /* for CONFIG_CPU_nn */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/hardware.h>
diff --git a/arch/arm26/lib/io-acorn.S b/arch/arm26/lib/io-acorn.S
index f6c3e30..5f62ade 100644
--- a/arch/arm26/lib/io-acorn.S
+++ b/arch/arm26/lib/io-acorn.S
@@ -7,7 +7,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/config.h> /* for CONFIG_CPU_nn */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/hardware.h>
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 49164e9..cced73c 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -10,6 +10,7 @@
 #include <linux/init.h>
 
 #include <asm/arch/board.h>
+#include <asm/arch/init.h>
 
 struct eth_platform_data __initdata eth0_data = {
 	.valid		= 1,
@@ -20,13 +21,22 @@
 
 extern struct lcdc_platform_data atstk1000_fb0_data;
 
+void __init setup_board(void)
+{
+	at32_map_usart(1, 0);	/* /dev/ttyS0 */
+	at32_map_usart(2, 1);	/* /dev/ttyS1 */
+	at32_map_usart(3, 2);	/* /dev/ttyS2 */
+
+	at32_setup_serial_console(0);
+}
+
 static int __init atstk1002_init(void)
 {
 	at32_add_system_devices();
 
-	at32_add_device_usart(1);	/* /dev/ttyS0 */
-	at32_add_device_usart(2);	/* /dev/ttyS1 */
-	at32_add_device_usart(3);	/* /dev/ttyS2 */
+	at32_add_device_usart(0);
+	at32_add_device_usart(1);
+	at32_add_device_usart(2);
 
 	at32_add_device_eth(0, &eth0_data);
 	at32_add_device_spi(0);
diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
index 1d22255..6c2c5e0 100644
--- a/arch/avr32/configs/atstk1002_defconfig
+++ b/arch/avr32/configs/atstk1002_defconfig
@@ -385,9 +385,9 @@
 #
 # Non-8250 serial port support
 #
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index 5d68f3c..ea2d1ff 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -292,6 +292,7 @@
 
 	setup_processor();
 	setup_platform();
+	setup_board();
 
 	cpu_clk = clk_get(NULL, "cpu");
 	if (IS_ERR(cpu_clk)) {
diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/at32ap.c
index f7cedf5..90f207e 100644
--- a/arch/avr32/mach-at32ap/at32ap.c
+++ b/arch/avr32/mach-at32ap/at32ap.c
@@ -48,9 +48,6 @@
 	at32_sm_init();
 	at32_clock_init();
 	at32_portmux_init();
-
-	/* FIXME: This doesn't belong here */
-	at32_setup_serial_console(1);
 }
 
 static int __init pdc_probe(struct platform_device *pdev)
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 37982b6..7ff6ad8 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -523,33 +523,49 @@
  *  USART
  * -------------------------------------------------------------------- */
 
-static struct resource usart0_resource[] = {
+static struct atmel_uart_data atmel_usart0_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+static struct resource atmel_usart0_resource[] = {
 	PBMEM(0xffe00c00),
 	IRQ(7),
 };
-DEFINE_DEV(usart, 0);
-DEV_CLK(usart, usart0, pba, 4);
+DEFINE_DEV_DATA(atmel_usart, 0);
+DEV_CLK(usart, atmel_usart0, pba, 4);
 
-static struct resource usart1_resource[] = {
+static struct atmel_uart_data atmel_usart1_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+static struct resource atmel_usart1_resource[] = {
 	PBMEM(0xffe01000),
 	IRQ(7),
 };
-DEFINE_DEV(usart, 1);
-DEV_CLK(usart, usart1, pba, 4);
+DEFINE_DEV_DATA(atmel_usart, 1);
+DEV_CLK(usart, atmel_usart1, pba, 4);
 
-static struct resource usart2_resource[] = {
+static struct atmel_uart_data atmel_usart2_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+static struct resource atmel_usart2_resource[] = {
 	PBMEM(0xffe01400),
 	IRQ(8),
 };
-DEFINE_DEV(usart, 2);
-DEV_CLK(usart, usart2, pba, 5);
+DEFINE_DEV_DATA(atmel_usart, 2);
+DEV_CLK(usart, atmel_usart2, pba, 5);
 
-static struct resource usart3_resource[] = {
+static struct atmel_uart_data atmel_usart3_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+static struct resource atmel_usart3_resource[] = {
 	PBMEM(0xffe01800),
 	IRQ(9),
 };
-DEFINE_DEV(usart, 3);
-DEV_CLK(usart, usart3, pba, 6);
+DEFINE_DEV_DATA(atmel_usart, 3);
+DEV_CLK(usart, atmel_usart3, pba, 6);
 
 static inline void configure_usart0_pins(void)
 {
@@ -575,51 +591,54 @@
 	portmux_set_func(PIOB, 17, FUNC_B);	/* TXD	*/
 }
 
-static struct platform_device *setup_usart(unsigned int id)
+static struct platform_device *at32_usarts[4];
+
+void __init at32_map_usart(unsigned int hw_id, unsigned int line)
 {
 	struct platform_device *pdev;
 
-	switch (id) {
+	switch (hw_id) {
 	case 0:
-		pdev = &usart0_device;
+		pdev = &atmel_usart0_device;
 		configure_usart0_pins();
 		break;
 	case 1:
-		pdev = &usart1_device;
+		pdev = &atmel_usart1_device;
 		configure_usart1_pins();
 		break;
 	case 2:
-		pdev = &usart2_device;
+		pdev = &atmel_usart2_device;
 		configure_usart2_pins();
 		break;
 	case 3:
-		pdev = &usart3_device;
+		pdev = &atmel_usart3_device;
 		configure_usart3_pins();
 		break;
 	default:
-		pdev = NULL;
-		break;
+		return;
 	}
 
-	return pdev;
+	if (PXSEG(pdev->resource[0].start) == P4SEG) {
+		/* Addresses in the P4 segment are permanently mapped 1:1 */
+		struct atmel_uart_data *data = pdev->dev.platform_data;
+		data->regs = (void __iomem *)pdev->resource[0].start;
+	}
+
+	pdev->id = line;
+	at32_usarts[line] = pdev;
 }
 
 struct platform_device *__init at32_add_device_usart(unsigned int id)
 {
-	struct platform_device *pdev;
-
-	pdev = setup_usart(id);
-	if (pdev)
-		platform_device_register(pdev);
-
-	return pdev;
+	platform_device_register(at32_usarts[id]);
+	return at32_usarts[id];
 }
 
-struct platform_device *at91_default_console_device;
+struct platform_device *atmel_default_console_device;
 
 void __init at32_setup_serial_console(unsigned int usart_id)
 {
-	at91_default_console_device = setup_usart(usart_id);
+	atmel_default_console_device = at32_usarts[usart_id];
 }
 
 /* --------------------------------------------------------------------
@@ -813,10 +832,10 @@
 	&pio1_mck,
 	&pio2_mck,
 	&pio3_mck,
-	&usart0_usart,
-	&usart1_usart,
-	&usart2_usart,
-	&usart3_usart,
+	&atmel_usart0_usart,
+	&atmel_usart1_usart,
+	&atmel_usart2_usart,
+	&atmel_usart3_usart,
 	&macb0_hclk,
 	&macb0_pclk,
 	&spi0_mck,
diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c
index 7e55884..44a9aeb 100644
--- a/arch/frv/kernel/time.c
+++ b/arch/frv/kernel/time.c
@@ -10,7 +10,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c
index e569d17..8abab3b 100644
--- a/arch/h8300/kernel/time.c
+++ b/arch/h8300/kernel/time.c
@@ -16,7 +16,6 @@
  *		"A Kernel Model for Precision Timekeeping" by Dave Mills
  */
 
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 1aaea6a..92f79cd 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -62,8 +62,6 @@
 #include <mach_mpparse.h>
 #endif				/* CONFIG_X86_LOCAL_APIC */
 
-static inline int gsi_irq_sharing(int gsi) { return gsi; }
-
 #endif				/* X86 */
 
 #define BAD_MADT_ENTRY(entry, end) (					    \
@@ -468,12 +466,7 @@
 
 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_irq_sharing(gsi);
+	*irq = gsi;
 	return 0;
 }
 
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index ea5f4e7..d07ed31 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -34,35 +34,15 @@
  * moves to arch independent land
  */
 
-DEFINE_SPINLOCK(i8259A_lock);
-
-static void end_8259A_irq (unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
-							irq_desc[irq].action)
-		enable_8259A_irq(irq);
-}
-
-#define shutdown_8259A_irq	disable_8259A_irq
-
 static int i8259A_auto_eoi;
-
+DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
-unsigned int startup_8259A_irq(unsigned int irq)
-{ 
-	enable_8259A_irq(irq);
-	return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type i8259A_irq_type = {
-	.typename = "XT-PIC",
-	.startup = startup_8259A_irq,
-	.shutdown = shutdown_8259A_irq,
-	.enable = enable_8259A_irq,
-	.disable = disable_8259A_irq,
-	.ack = mask_and_ack_8259A,
-	.end = end_8259A_irq,
+static struct irq_chip i8259A_chip = {
+	.name		= "XT-PIC",
+	.mask		= disable_8259A_irq,
+	.unmask		= enable_8259A_irq,
+	.mask_ack	= mask_and_ack_8259A,
 };
 
 /*
@@ -133,7 +113,7 @@
 {
 	disable_irq_nosync(irq);
 	io_apic_irqs &= ~(1<<irq);
-	irq_desc[irq].chip = &i8259A_irq_type;
+	set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
 	enable_irq(irq);
 }
 
@@ -327,12 +307,12 @@
 	outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
 	if (auto_eoi)
 		/*
-		 * in AEOI mode we just have to mask the interrupt
+		 * In AEOI mode we just have to mask the interrupt
 		 * when acking.
 		 */
-		i8259A_irq_type.ack = disable_8259A_irq;
+		i8259A_chip.mask_ack = disable_8259A_irq;
 	else
-		i8259A_irq_type.ack = mask_and_ack_8259A;
+		i8259A_chip.mask_ack = mask_and_ack_8259A;
 
 	udelay(100);		/* wait for 8259A to initialize */
 
@@ -389,12 +369,13 @@
 			/*
 			 * 16 old-style INTA-cycle interrupts:
 			 */
-			irq_desc[i].chip = &i8259A_irq_type;
+			set_irq_chip_and_handler(i, &i8259A_chip,
+						 handle_level_irq);
 		} else {
 			/*
 			 * 'high' PCI IRQs filled in on demand
 			 */
-			irq_desc[i].chip = &no_irq_type;
+			irq_desc[i].chip = &no_irq_chip;
 		}
 	}
 }
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index fd0df75..b7287fb 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -31,6 +31,9 @@
 #include <linux/acpi.h>
 #include <linux/module.h>
 #include <linux/sysdev.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/htirq.h>
 
 #include <asm/io.h>
 #include <asm/smp.h>
@@ -38,6 +41,8 @@
 #include <asm/timer.h>
 #include <asm/i8259.h>
 #include <asm/nmi.h>
+#include <asm/msidef.h>
+#include <asm/hypertransport.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
@@ -86,15 +91,6 @@
 	int apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
-#ifdef CONFIG_PCI_MSI
-#define vector_to_irq(vector) 	\
-	(platform_legacy_irq(vector) ? vector : vector_irq[vector])
-#else
-#define vector_to_irq(vector)	(vector)
-#endif
-
-
 union entry_union {
 	struct { u32 w1, w2; };
 	struct IO_APIC_route_entry entry;
@@ -280,7 +276,7 @@
 			break;
 		entry = irq_2_pin + entry->next;
 	}
-	set_irq_info(irq, cpumask);
+	set_native_irq_info(irq, cpumask);
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
@@ -1181,46 +1177,45 @@
 /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
 u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
 
-int assign_irq_vector(int irq)
+static int __assign_irq_vector(int irq)
 {
 	static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
-	unsigned long flags;
 	int vector;
 
-	BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+	BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
 
-	spin_lock_irqsave(&vector_lock, flags);
-
-	if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
-		spin_unlock_irqrestore(&vector_lock, flags);
+	if (IO_APIC_VECTOR(irq) > 0)
 		return IO_APIC_VECTOR(irq);
-	}
-next:
+
 	current_vector += 8;
 	if (current_vector == SYSCALL_VECTOR)
-		goto next;
+		current_vector += 8;
 
 	if (current_vector >= FIRST_SYSTEM_VECTOR) {
 		offset++;
-		if (!(offset%8)) {
-			spin_unlock_irqrestore(&vector_lock, flags);
+		if (!(offset % 8))
 			return -ENOSPC;
-		}
 		current_vector = FIRST_DEVICE_VECTOR + offset;
 	}
 
 	vector = current_vector;
-	vector_irq[vector] = irq;
-	if (irq != AUTO_ASSIGN)
-		IO_APIC_VECTOR(irq) = vector;
-
-	spin_unlock_irqrestore(&vector_lock, flags);
+	IO_APIC_VECTOR(irq) = vector;
 
 	return vector;
 }
 
-static struct hw_interrupt_type ioapic_level_type;
-static struct hw_interrupt_type ioapic_edge_type;
+static int assign_irq_vector(int irq)
+{
+	unsigned long flags;
+	int vector;
+
+	spin_lock_irqsave(&vector_lock, flags);
+	vector = __assign_irq_vector(irq);
+	spin_unlock_irqrestore(&vector_lock, flags);
+
+	return vector;
+}
+static struct irq_chip ioapic_chip;
 
 #define IOAPIC_AUTO	-1
 #define IOAPIC_EDGE	0
@@ -1228,16 +1223,14 @@
 
 static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-	unsigned idx;
-
-	idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
-
 	if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
 			trigger == IOAPIC_LEVEL)
-		irq_desc[idx].chip = &ioapic_level_type;
+		set_irq_chip_and_handler(irq, &ioapic_chip,
+					 handle_fasteoi_irq);
 	else
-		irq_desc[idx].chip = &ioapic_edge_type;
-	set_intr_gate(vector, interrupt[idx]);
+		set_irq_chip_and_handler(irq, &ioapic_chip,
+					 handle_edge_irq);
+	set_intr_gate(vector, interrupt[irq]);
 }
 
 static void __init setup_IO_APIC_irqs(void)
@@ -1346,7 +1339,8 @@
 	 * The timer IRQ doesn't have to know that behind the
 	 * scene we have a 8259A-master in AEOI mode ...
 	 */
-	irq_desc[0].chip = &ioapic_edge_type;
+	irq_desc[0].chip = &ioapic_chip;
+	set_irq_handler(0, handle_edge_irq);
 
 	/*
 	 * Add it to the IO-APIC irq-routing table:
@@ -1481,17 +1475,12 @@
 		);
 	}
 	}
-	if (use_pci_vector())
-		printk(KERN_INFO "Using vector-based indexing\n");
 	printk(KERN_DEBUG "IRQ to pin mappings:\n");
 	for (i = 0; i < NR_IRQS; i++) {
 		struct irq_pin_list *entry = irq_2_pin + i;
 		if (entry->pin < 0)
 			continue;
- 		if (use_pci_vector() && !platform_legacy_irq(i))
-			printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
-		else
-			printk(KERN_DEBUG "IRQ%d ", i);
+		printk(KERN_DEBUG "IRQ%d ", i);
 		for (;;) {
 			printk("-> %d:%d", entry->apic, entry->pin);
 			if (!entry->next)
@@ -1918,6 +1907,8 @@
  */
 
 /*
+ * Startup quirk:
+ *
  * Starting up a edge-triggered IO-APIC interrupt is
  * nasty - we need to make sure that we get the edge.
  * If it is already asserted for some reason, we need
@@ -1925,8 +1916,10 @@
  *
  * This is not complete - we should be able to fake
  * an edge even if it isn't on the 8259A...
+ *
+ * (We do this for level-triggered IRQs too - it cannot hurt.)
  */
-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(unsigned int irq)
 {
 	int was_pending = 0;
 	unsigned long flags;
@@ -1943,47 +1936,18 @@
 	return was_pending;
 }
 
-/*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
-static void ack_edge_ioapic_irq(unsigned int irq)
+static void ack_ioapic_irq(unsigned int irq)
 {
-	move_irq(irq);
-	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
-					== (IRQ_PENDING | IRQ_DISABLED))
-		mask_IO_APIC_irq(irq);
+	move_native_irq(irq);
 	ack_APIC_irq();
 }
 
-/*
- * Level triggered interrupts can just be masked,
- * and shutting down and starting up the interrupt
- * is the same as enabling and disabling them -- except
- * with a startup need to return a "was pending" value.
- *
- * Level triggered interrupts are special because we
- * do not touch any IO-APIC register while handling
- * them. We ack the APIC in the end-IRQ handler, not
- * in the start-IRQ-handler. Protection against reentrance
- * from the same interrupt is still provided, both by the
- * generic IRQ layer and by the fact that an unacked local
- * APIC does not accept IRQs.
- */
-static unsigned int startup_level_ioapic_irq (unsigned int irq)
-{
-	unmask_IO_APIC_irq(irq);
-
-	return 0; /* don't check for pending */
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
+static void ack_ioapic_quirk_irq(unsigned int irq)
 {
 	unsigned long v;
 	int i;
 
-	move_irq(irq);
+	move_native_irq(irq);
 /*
  * It appears there is an erratum which affects at least version 0x11
  * of I/O APIC (that's the 82093AA and cores integrated into various
@@ -2018,105 +1982,26 @@
 	}
 }
 
-#ifdef CONFIG_PCI_MSI
-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	return startup_edge_ioapic_irq(irq);
-}
-
-static void ack_edge_ioapic_vector(unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	move_native_irq(vector);
-	ack_edge_ioapic_irq(irq);
-}
-
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	return startup_level_ioapic_irq (irq);
-}
-
-static void end_level_ioapic_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	move_native_irq(vector);
-	end_level_ioapic_irq(irq);
-}
-
-static void mask_IO_APIC_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	mask_IO_APIC_irq(irq);
-}
-
-static void unmask_IO_APIC_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	unmask_IO_APIC_irq(irq);
-}
-
-#ifdef CONFIG_SMP
-static void set_ioapic_affinity_vector (unsigned int vector,
-					cpumask_t cpu_mask)
-{
-	int irq = vector_to_irq(vector);
-
-	set_native_irq_info(vector, cpu_mask);
-	set_ioapic_affinity_irq(irq, cpu_mask);
-}
-#endif
-#endif
-
-static int ioapic_retrigger(unsigned int irq)
+static int ioapic_retrigger_irq(unsigned int irq)
 {
 	send_IPI_self(IO_APIC_VECTOR(irq));
 
 	return 1;
 }
 
-/*
- * Level and edge triggered IO-APIC interrupts need different handling,
- * so we use two separate IRQ descriptors. Edge triggered IRQs can be
- * handled with the level-triggered descriptor, but that one has slightly
- * more overhead. Level-triggered interrupts cannot be handled with the
- * edge-triggered handler, without risking IRQ storms and other ugly
- * races.
- */
-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
-	.typename 	= "IO-APIC-edge",
-	.startup 	= startup_edge_ioapic,
-	.shutdown 	= shutdown_edge_ioapic,
-	.enable 	= enable_edge_ioapic,
-	.disable 	= disable_edge_ioapic,
-	.ack 		= ack_edge_ioapic,
-	.end 		= end_edge_ioapic,
+static struct irq_chip ioapic_chip __read_mostly = {
+	.name 		= "IO-APIC",
+	.startup 	= startup_ioapic_irq,
+	.mask	 	= mask_IO_APIC_irq,
+	.unmask	 	= unmask_IO_APIC_irq,
+	.ack 		= ack_ioapic_irq,
+	.eoi 		= ack_ioapic_quirk_irq,
 #ifdef CONFIG_SMP
-	.set_affinity 	= set_ioapic_affinity,
+	.set_affinity 	= set_ioapic_affinity_irq,
 #endif
-	.retrigger	= ioapic_retrigger,
+	.retrigger	= ioapic_retrigger_irq,
 };
 
-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
-	.typename 	= "IO-APIC-level",
-	.startup 	= startup_level_ioapic,
-	.shutdown 	= shutdown_level_ioapic,
-	.enable 	= enable_level_ioapic,
-	.disable 	= disable_level_ioapic,
-	.ack 		= mask_and_ack_level_ioapic,
-	.end 		= end_level_ioapic,
-#ifdef CONFIG_SMP
-	.set_affinity 	= set_ioapic_affinity,
-#endif
-	.retrigger	= ioapic_retrigger,
-};
 
 static inline void init_IO_APIC_traps(void)
 {
@@ -2135,11 +2020,6 @@
 	 */
 	for (irq = 0; irq < NR_IRQS ; irq++) {
 		int tmp = irq;
-		if (use_pci_vector()) {
-			if (!platform_legacy_irq(tmp))
-				if ((tmp = vector_to_irq(tmp)) == -1)
-					continue;
-		}
 		if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
 			/*
 			 * Hmm.. We don't have an entry for this,
@@ -2150,20 +2030,21 @@
 				make_8259A_irq(irq);
 			else
 				/* Strange. Oh, well.. */
-				irq_desc[irq].chip = &no_irq_type;
+				irq_desc[irq].chip = &no_irq_chip;
 		}
 	}
 }
 
-static void enable_lapic_irq (unsigned int irq)
-{
-	unsigned long v;
+/*
+ * The local APIC irq-chip implementation:
+ */
 
-	v = apic_read(APIC_LVT0);
-	apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+static void ack_apic(unsigned int irq)
+{
+	ack_APIC_irq();
 }
 
-static void disable_lapic_irq (unsigned int irq)
+static void mask_lapic_irq (unsigned int irq)
 {
 	unsigned long v;
 
@@ -2171,21 +2052,19 @@
 	apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
 }
 
-static void ack_lapic_irq (unsigned int irq)
+static void unmask_lapic_irq (unsigned int irq)
 {
-	ack_APIC_irq();
+	unsigned long v;
+
+	v = apic_read(APIC_LVT0);
+	apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
 }
 
-static void end_lapic_irq (unsigned int i) { /* nothing */ }
-
-static struct hw_interrupt_type lapic_irq_type __read_mostly = {
-	.typename 	= "local-APIC-edge",
-	.startup 	= NULL, /* startup_irq() not used for IRQ0 */
-	.shutdown 	= NULL, /* shutdown_irq() not used for IRQ0 */
-	.enable 	= enable_lapic_irq,
-	.disable 	= disable_lapic_irq,
-	.ack 		= ack_lapic_irq,
-	.end 		= end_lapic_irq
+static struct irq_chip lapic_chip __read_mostly = {
+	.name		= "local-APIC-edge",
+	.mask		= mask_lapic_irq,
+	.unmask		= unmask_lapic_irq,
+	.eoi		= ack_apic,
 };
 
 static void setup_nmi (void)
@@ -2356,7 +2235,7 @@
 	printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
 	disable_8259A_irq(0);
-	irq_desc[0].chip = &lapic_irq_type;
+	set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq);
 	apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);	/* Fixed mode */
 	enable_8259A_irq(0);
 
@@ -2531,6 +2410,238 @@
 
 device_initcall(ioapic_init_sysfs);
 
+/*
+ * Dynamic irq allocate and deallocation
+ */
+int create_irq(void)
+{
+	/* Allocate an unused irq */
+	int irq, new, vector;
+	unsigned long flags;
+
+	irq = -ENOSPC;
+	spin_lock_irqsave(&vector_lock, flags);
+	for (new = (NR_IRQS - 1); new >= 0; new--) {
+		if (platform_legacy_irq(new))
+			continue;
+		if (irq_vector[new] != 0)
+			continue;
+		vector = __assign_irq_vector(new);
+		if (likely(vector > 0))
+			irq = new;
+		break;
+	}
+	spin_unlock_irqrestore(&vector_lock, flags);
+
+	if (irq >= 0) {
+		set_intr_gate(vector, interrupt[irq]);
+		dynamic_irq_init(irq);
+	}
+	return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	dynamic_irq_cleanup(irq);
+
+	spin_lock_irqsave(&vector_lock, flags);
+	irq_vector[irq] = 0;
+	spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+/*
+ * MSI mesage composition
+ */
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+{
+	int vector;
+	unsigned dest;
+
+	vector = assign_irq_vector(irq);
+	if (vector >= 0) {
+		dest = cpu_mask_to_apicid(TARGET_CPUS);
+
+		msg->address_hi = MSI_ADDR_BASE_HI;
+		msg->address_lo =
+			MSI_ADDR_BASE_LO |
+			((INT_DEST_MODE == 0) ?
+				MSI_ADDR_DEST_MODE_PHYSICAL:
+				MSI_ADDR_DEST_MODE_LOGICAL) |
+			((INT_DELIVERY_MODE != dest_LowestPrio) ?
+				MSI_ADDR_REDIRECTION_CPU:
+				MSI_ADDR_REDIRECTION_LOWPRI) |
+			MSI_ADDR_DEST_ID(dest);
+
+		msg->data =
+			MSI_DATA_TRIGGER_EDGE |
+			MSI_DATA_LEVEL_ASSERT |
+			((INT_DELIVERY_MODE != dest_LowestPrio) ?
+				MSI_DATA_DELIVERY_FIXED:
+				MSI_DATA_DELIVERY_LOWPRI) |
+			MSI_DATA_VECTOR(vector);
+	}
+	return vector;
+}
+
+#ifdef CONFIG_SMP
+static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+	struct msi_msg msg;
+	unsigned int dest;
+	cpumask_t tmp;
+	int vector;
+
+	cpus_and(tmp, mask, cpu_online_map);
+	if (cpus_empty(tmp))
+		tmp = TARGET_CPUS;
+
+	vector = assign_irq_vector(irq);
+	if (vector < 0)
+		return;
+
+	dest = cpu_mask_to_apicid(mask);
+
+	read_msi_msg(irq, &msg);
+
+	msg.data &= ~MSI_DATA_VECTOR_MASK;
+	msg.data |= MSI_DATA_VECTOR(vector);
+	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+	msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+	write_msi_msg(irq, &msg);
+	set_native_irq_info(irq, mask);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip msi_chip = {
+	.name		= "PCI-MSI",
+	.unmask		= unmask_msi_irq,
+	.mask		= mask_msi_irq,
+	.ack		= ack_ioapic_irq,
+#ifdef CONFIG_SMP
+	.set_affinity	= set_msi_irq_affinity,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
+};
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+{
+	struct msi_msg msg;
+	int ret;
+	ret = msi_compose_msg(dev, irq, &msg);
+	if (ret < 0)
+		return ret;
+
+	write_msi_msg(irq, &msg);
+
+	set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq);
+
+	return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	return;
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+/*
+ * Hypertransport interrupt support
+ */
+#ifdef CONFIG_HT_IRQ
+
+#ifdef CONFIG_SMP
+
+static void target_ht_irq(unsigned int irq, unsigned int dest)
+{
+	u32 low, high;
+	low  = read_ht_irq_low(irq);
+	high = read_ht_irq_high(irq);
+
+	low  &= ~(HT_IRQ_LOW_DEST_ID_MASK);
+	high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+
+	low  |= HT_IRQ_LOW_DEST_ID(dest);
+	high |= HT_IRQ_HIGH_DEST_ID(dest);
+
+	write_ht_irq_low(irq, low);
+	write_ht_irq_high(irq, high);
+}
+
+static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+	unsigned int dest;
+	cpumask_t tmp;
+
+	cpus_and(tmp, mask, cpu_online_map);
+	if (cpus_empty(tmp))
+		tmp = TARGET_CPUS;
+
+	cpus_and(mask, tmp, CPU_MASK_ALL);
+
+	dest = cpu_mask_to_apicid(mask);
+
+	target_ht_irq(irq, dest);
+	set_native_irq_info(irq, mask);
+}
+#endif
+
+static struct hw_interrupt_type ht_irq_chip = {
+	.name		= "PCI-HT",
+	.mask		= mask_ht_irq,
+	.unmask		= unmask_ht_irq,
+	.ack		= ack_ioapic_irq,
+#ifdef CONFIG_SMP
+	.set_affinity	= set_ht_irq_affinity,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
+};
+
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+{
+	int vector;
+
+	vector = assign_irq_vector(irq);
+	if (vector >= 0) {
+		u32 low, high;
+		unsigned dest;
+		cpumask_t tmp;
+
+		cpus_clear(tmp);
+		cpu_set(vector >> 8, tmp);
+		dest = cpu_mask_to_apicid(tmp);
+
+		high = 	HT_IRQ_HIGH_DEST_ID(dest);
+
+		low =	HT_IRQ_LOW_BASE |
+			HT_IRQ_LOW_DEST_ID(dest) |
+			HT_IRQ_LOW_VECTOR(vector) |
+			((INT_DEST_MODE == 0) ?
+				HT_IRQ_LOW_DM_PHYSICAL :
+				HT_IRQ_LOW_DM_LOGICAL) |
+			HT_IRQ_LOW_RQEOI_EDGE |
+			((INT_DELIVERY_MODE != dest_LowestPrio) ?
+				HT_IRQ_LOW_MT_FIXED :
+				HT_IRQ_LOW_MT_ARBITRATED) |
+			HT_IRQ_LOW_IRQ_MASKED;
+
+		write_ht_irq_low(irq, low);
+		write_ht_irq_high(irq, high);
+
+		set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq);
+	}
+	return vector;
+}
+#endif /* CONFIG_HT_IRQ */
+
 /* --------------------------------------------------------------------------
                           ACPI-based IOAPIC Configuration
    -------------------------------------------------------------------------- */
@@ -2684,7 +2795,7 @@
 
 	ioapic_write_entry(ioapic, pin, entry);
 	spin_lock_irqsave(&ioapic_lock, flags);
-	set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
+	set_native_irq_info(irq, TARGET_CPUS);
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 
 	return 0;
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 5fe547c..3dd2e18 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -55,6 +55,7 @@
 {	
 	/* high bit used in ret_from_ code */
 	int irq = ~regs->orig_eax;
+	struct irq_desc *desc = irq_desc + irq;
 #ifdef CONFIG_4KSTACKS
 	union irq_ctx *curctx, *irqctx;
 	u32 *isp;
@@ -94,7 +95,7 @@
 	 * current stack (which is the irq stack already after all)
 	 */
 	if (curctx != irqctx) {
-		int arg1, arg2, ebx;
+		int arg1, arg2, arg3, ebx;
 
 		/* build the stack frame on the IRQ stack */
 		isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
@@ -110,16 +111,17 @@
 			(curctx->tinfo.preempt_count & SOFTIRQ_MASK);
 
 		asm volatile(
-			"       xchgl   %%ebx,%%esp      \n"
-			"       call    __do_IRQ         \n"
+			"       xchgl  %%ebx,%%esp      \n"
+			"       call   *%%edi           \n"
 			"       movl   %%ebx,%%esp      \n"
-			: "=a" (arg1), "=d" (arg2), "=b" (ebx)
-			:  "0" (irq),   "1" (regs),  "2" (isp)
-			: "memory", "cc", "ecx"
+			: "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx)
+			:  "0" (irq),   "1" (desc),  "2" (regs),  "3" (isp),
+			   "D" (desc->handle_irq)
+			: "memory", "cc"
 		);
 	} else
 #endif
-		__do_IRQ(irq, regs);
+		desc->handle_irq(irq, desc, regs);
 
 	irq_exit();
 
@@ -253,7 +255,8 @@
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-		seq_printf(p, " %14s", irq_desc[i].chip->typename);
+		seq_printf(p, " %8s", irq_desc[i].chip->name);
+		seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
 		seq_printf(p, "  %s", action->name);
 
 		for (action=action->next; action; action = action->next)
diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S
index 01f80b5..ef6ad9e 100644
--- a/arch/i386/lib/semaphore.S
+++ b/arch/i386/lib/semaphore.S
@@ -13,7 +13,6 @@
  * rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
  */
 
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/rwlock.h>
 #include <asm/alternative-asm.i>
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 4a8995c..47f02af 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -981,10 +981,6 @@
 							pci_name(bridge), 'A' + pin, irq);
 				}
 				if (irq >= 0) {
-					if (use_pci_vector() &&
-						!platform_legacy_irq(irq))
-						irq = IO_APIC_VECTOR(irq);
-
 					printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
 						pci_name(dev), 'A' + pin, irq);
 					dev->irq = irq;
@@ -1169,33 +1165,3 @@
 	}
 	return 0;
 }
-
-int pci_vector_resources(int last, int nr_released)
-{
-	int count = nr_released;
-
-	int next = last;
-	int offset = (last % 8);
-
-	while (next < FIRST_SYSTEM_VECTOR) {
-		next += 8;
-#ifdef CONFIG_X86_64
-		if (next == IA32_SYSCALL_VECTOR)
-			continue;
-#else
-		if (next == SYSCALL_VECTOR)
-			continue;
-#endif
-		count++;
-		if (next >= FIRST_SYSTEM_VECTOR) {
-			if (offset%8) {
-				next = FIRST_DEVICE_VECTOR + offset;
-				offset++;
-				continue;
-			}
-			count--;
-		}
-	}
-
-	return count;
-}
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 3149749..cfa099b 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -30,6 +30,7 @@
 obj-$(CONFIG_KPROBES)		+= kprobes.o jprobes.o
 obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR)	+= uncached.o
 obj-$(CONFIG_AUDIT)		+= audit.o
+obj-$(CONFIG_PCI_MSI)		+= msi_ia64.o
 mca_recovery-y			+= mca_drv.o mca_drv_asm.o
 
 obj-$(CONFIG_IA64_ESI)		+= esi.o
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index aafca18..ab2d19c 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -30,6 +30,7 @@
 #include <linux/smp_lock.h>
 #include <linux/threads.h>
 #include <linux/bitops.h>
+#include <linux/irq.h>
 
 #include <asm/delay.h>
 #include <asm/intrinsics.h>
@@ -105,6 +106,25 @@
 	return test_and_set_bit(pos, ia64_vector_mask);
 }
 
+/*
+ * Dynamic irq allocate and deallocation for MSI
+ */
+int create_irq(void)
+{
+	int vector = assign_irq_vector(AUTO_ASSIGN);
+
+	if (vector >= 0)
+		dynamic_irq_init(vector);
+
+	return vector;
+}
+
+void destroy_irq(unsigned int irq)
+{
+	dynamic_irq_cleanup(irq);
+	free_irq_vector(irq);
+}
+
 #ifdef CONFIG_SMP
 #	define IS_RESCHEDULE(vec)	(vec == IA64_IPI_RESCHEDULE)
 #else
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
new file mode 100644
index 0000000..822e59a
--- /dev/null
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -0,0 +1,143 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <asm/smp.h>
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT		8
+#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
+#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
+#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_TARGET_CPU_SHIFT		4
+#define MSI_ADDR_HEADER			0xfee00000
+
+#define MSI_ADDR_DESTID_MASK		0xfff0000f
+#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT		2
+#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
+#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+static struct irq_chip	ia64_msi_chip;
+
+#ifdef CONFIG_SMP
+static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
+{
+	struct msi_msg msg;
+	u32 addr;
+
+	read_msi_msg(irq, &msg);
+
+	addr = msg.address_lo;
+	addr &= MSI_ADDR_DESTID_MASK;
+	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+	msg.address_lo = addr;
+
+	write_msi_msg(irq, &msg);
+	set_native_irq_info(irq, cpu_mask);
+}
+#endif /* CONFIG_SMP */
+
+int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+	struct msi_msg	msg;
+	unsigned long	dest_phys_id;
+	unsigned int	vector;
+
+	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+	vector = irq;
+
+	msg.address_hi = 0;
+	msg.address_lo =
+		MSI_ADDR_HEADER |
+		MSI_ADDR_DESTMODE_PHYS |
+		MSI_ADDR_REDIRECTION_CPU |
+		MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+	msg.data =
+		MSI_DATA_TRIGGER_EDGE |
+		MSI_DATA_LEVEL_ASSERT |
+		MSI_DATA_DELIVERY_FIXED |
+		MSI_DATA_VECTOR(vector);
+
+	write_msi_msg(irq, &msg);
+	set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
+
+	return 0;
+}
+
+void ia64_teardown_msi_irq(unsigned int irq)
+{
+	return;		/* no-op */
+}
+
+static void ia64_ack_msi_irq(unsigned int irq)
+{
+	move_native_irq(irq);
+	ia64_eoi();
+}
+
+static int ia64_msi_retrigger_irq(unsigned int irq)
+{
+	unsigned int vector = irq;
+	ia64_resend_irq(vector);
+
+	return 1;
+}
+
+/*
+ * Generic ops used on most IA64 platforms.
+ */
+static struct irq_chip ia64_msi_chip = {
+	.name		= "PCI-MSI",
+	.mask		= mask_msi_irq,
+	.unmask		= unmask_msi_irq,
+	.ack		= ia64_ack_msi_irq,
+#ifdef CONFIG_SMP
+	.set_affinity	= ia64_set_msi_irq_affinity,
+#endif
+	.retrigger	= ia64_msi_retrigger_irq,
+};
+
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+	if (platform_setup_msi_irq)
+		return platform_setup_msi_irq(irq, pdev);
+
+	return ia64_setup_msi_irq(irq, pdev);
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	if (platform_teardown_msi_irq)
+		return platform_teardown_msi_irq(irq);
+
+	return ia64_teardown_msi_irq(irq);
+}
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 15c7c67..b30be7c 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -810,12 +810,3 @@
 	}
 	return rc;
 }
-
-int pci_vector_resources(int last, int nr_released)
-{
-	int count = nr_released;
-
-	count += (IA64_LAST_DEVICE_VECTOR - last);
-
-	return count;
-}
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile
index ab9c48c..2d78f34 100644
--- a/arch/ia64/sn/kernel/Makefile
+++ b/arch/ia64/sn/kernel/Makefile
@@ -19,3 +19,4 @@
 obj-$(CONFIG_IA64_SGI_SN_XP)	+= xpc.o
 xpc-y				:= xpc_main.o xpc_channel.o xpc_partition.o
 obj-$(CONFIG_IA64_SGI_SN_XP)	+= xpnet.o
+obj-$(CONFIG_PCI_MSI)		+= msi_sn.o
diff --git a/drivers/pci/msi-altix.c b/arch/ia64/sn/kernel/msi_sn.c
similarity index 65%
rename from drivers/pci/msi-altix.c
rename to arch/ia64/sn/kernel/msi_sn.c
index bed4183..6ffd1f8 100644
--- a/drivers/pci/msi-altix.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -7,8 +7,10 @@
  */
 
 #include <linux/types.h>
+#include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/cpumask.h>
+#include <linux/msi.h>
 
 #include <asm/sn/addrs.h>
 #include <asm/sn/intr.h>
@@ -16,17 +18,16 @@
 #include <asm/sn/pcidev.h>
 #include <asm/sn/nodepda.h>
 
-#include "msi.h"
-
 struct sn_msi_info {
 	u64 pci_addr;
 	struct sn_irq_info *sn_irq_info;
 };
 
-static struct sn_msi_info *sn_msi_info;
+static struct sn_msi_info sn_msi_info[NR_IRQS];
 
-static void
-sn_msi_teardown(unsigned int vector)
+static struct irq_chip sn_msi_chip;
+
+void sn_teardown_msi_irq(unsigned int irq)
 {
 	nasid_t nasid;
 	int widget;
@@ -36,7 +37,7 @@
 	struct pcibus_bussoft *bussoft;
 	struct sn_pcibus_provider *provider;
 
-	sn_irq_info = sn_msi_info[vector].sn_irq_info;
+	sn_irq_info = sn_msi_info[irq].sn_irq_info;
 	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
 		return;
 
@@ -45,9 +46,9 @@
 	provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
 	(*provider->dma_unmap)(pdev,
-			       sn_msi_info[vector].pci_addr,
+			       sn_msi_info[irq].pci_addr,
 			       PCI_DMA_FROMDEVICE);
-	sn_msi_info[vector].pci_addr = 0;
+	sn_msi_info[irq].pci_addr = 0;
 
 	bussoft = SN_PCIDEV_BUSSOFT(pdev);
 	nasid = NASID_GET(bussoft->bs_base);
@@ -56,15 +57,15 @@
 			SWIN_WIDGETNUM(bussoft->bs_base);
 
 	sn_intr_free(nasid, widget, sn_irq_info);
-	sn_msi_info[vector].sn_irq_info = NULL;
+	sn_msi_info[irq].sn_irq_info = NULL;
 
 	return;
 }
 
-int
-sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
-	     u32 *addr_hi, u32 *addr_lo, u32 *data)
+int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
 {
+	struct msi_msg msg;
+	struct msi_desc *entry;
 	int widget;
 	int status;
 	nasid_t nasid;
@@ -73,6 +74,10 @@
 	struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
 	struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
+	entry = get_irq_data(irq);
+	if (!entry->msi_attrib.is_64)
+		return -EINVAL;
+
 	if (bussoft == NULL)
 		return -EINVAL;
 
@@ -93,7 +98,7 @@
 	if (! sn_irq_info)
 		return -ENOMEM;
 
-	status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
+	status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
 	if (status) {
 		kfree(sn_irq_info);
 		return -ENOMEM;
@@ -119,29 +124,32 @@
 		return -ENOMEM;
 	}
 
-	sn_msi_info[vector].sn_irq_info = sn_irq_info;
-	sn_msi_info[vector].pci_addr = bus_addr;
+	sn_msi_info[irq].sn_irq_info = sn_irq_info;
+	sn_msi_info[irq].pci_addr = bus_addr;
 
-	*addr_hi = (u32)(bus_addr >> 32);
-	*addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+	msg.address_hi = (u32)(bus_addr >> 32);
+	msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
 
 	/*
 	 * In the SN platform, bit 16 is a "send vector" bit which
 	 * must be present in order to move the vector through the system.
 	 */
-	*data = 0x100 + (unsigned int)vector;
+	msg.data = 0x100 + irq;
 
 #ifdef CONFIG_SMP
-	set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
+	set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
 #endif
 
+	write_msi_msg(irq, &msg);
+	set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
+
 	return 0;
 }
 
-static void
-sn_msi_target(unsigned int vector, unsigned int cpu,
-	      u32 *addr_hi, u32 *addr_lo)
+#ifdef CONFIG_SMP
+static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
 {
+	struct msi_msg msg;
 	int slice;
 	nasid_t nasid;
 	u64 bus_addr;
@@ -150,8 +158,10 @@
 	struct sn_irq_info *sn_irq_info;
 	struct sn_irq_info *new_irq_info;
 	struct sn_pcibus_provider *provider;
+	unsigned int cpu;
 
-	sn_irq_info = sn_msi_info[vector].sn_irq_info;
+	cpu = first_cpu(cpu_mask);
+	sn_irq_info = sn_msi_info[irq].sn_irq_info;
 	if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
 		return;
 
@@ -159,19 +169,20 @@
 	 * Release XIO resources for the old MSI PCI address
 	 */
 
+	read_msi_msg(irq, &msg);
         sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
 	pdev = sn_pdev->pdi_linux_pcidev;
 	provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
-	bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
+	bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo);
 	(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
-	sn_msi_info[vector].pci_addr = 0;
+	sn_msi_info[irq].pci_addr = 0;
 
 	nasid = cpuid_to_nasid(cpu);
 	slice = cpuid_to_slice(cpu);
 
 	new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
-	sn_msi_info[vector].sn_irq_info = new_irq_info;
+	sn_msi_info[irq].sn_irq_info = new_irq_info;
 	if (new_irq_info == NULL)
 		return;
 
@@ -184,27 +195,36 @@
 					sizeof(new_irq_info->irq_xtalkaddr),
 					SN_DMA_MSI|SN_DMA_ADDR_XIO);
 
-	sn_msi_info[vector].pci_addr = bus_addr;
-	*addr_hi = (u32)(bus_addr >> 32);
-	*addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+	sn_msi_info[irq].pci_addr = bus_addr;
+	msg.address_hi = (u32)(bus_addr >> 32);
+	msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+	write_msi_msg(irq, &msg);
+	set_native_irq_info(irq, cpu_mask);
 }
+#endif /* CONFIG_SMP */
 
-struct msi_ops sn_msi_ops = {
-	.setup = sn_msi_setup,
-	.teardown = sn_msi_teardown,
-#ifdef CONFIG_SMP
-	.target = sn_msi_target,
-#endif
-};
-
-int
-sn_msi_init(void)
+static void sn_ack_msi_irq(unsigned int irq)
 {
-	sn_msi_info =
-		kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
-	if (! sn_msi_info)
-		return -ENOMEM;
-
-	msi_register(&sn_msi_ops);
-	return 0;
+	move_native_irq(irq);
+	ia64_eoi();
 }
+
+static int sn_msi_retrigger_irq(unsigned int irq)
+{
+	unsigned int vector = irq;
+	ia64_resend_irq(vector);
+
+	return 1;
+}
+
+static struct irq_chip sn_msi_chip = {
+	.name		= "PCI-MSI",
+	.mask		= mask_msi_irq,
+	.unmask		= unmask_msi_irq,
+	.ack		= sn_ack_msi_irq,
+#ifdef CONFIG_SMP
+	.set_affinity	= sn_set_msi_irq_affinity,
+#endif
+	.retrigger	= sn_msi_retrigger_irq,
+};
diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S
index 0c28f11..9a4d40b 100644
--- a/arch/m32r/mm/mmu.S
+++ b/arch/m32r/mm/mmu.S
@@ -6,7 +6,6 @@
 
 /* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */
 
-#include <linux/config.h>	/* CONFIG_MMU */
 #include <linux/linkage.h>
 #include <asm/assembler.h>
 #include <asm/smp.h>
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 6cfc984..28b2fef 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -10,7 +10,6 @@
  *		"A Kernel Model for Precision Timekeeping" by Dave Mills
  */
 
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/sched.h>
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
index ceef9bc..c7d6ad5 100644
--- a/arch/m68knommu/platform/532x/config.c
+++ b/arch/m68knommu/platform/532x/config.c
@@ -17,7 +17,6 @@
 
 /***************************************************************************/
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/param.h>
diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68knommu/platform/68328/romvec.S
index 3e7fe1e..3108446 100644
--- a/arch/m68knommu/platform/68328/romvec.S
+++ b/arch/m68knommu/platform/68328/romvec.S
@@ -10,8 +10,6 @@
  * Copyright 2006 Greg Ungerer <gerg@snapgear.com>
  */
 
-#include <linux/config.h>
-
 .global _start
 .global _buserr
 .global trap
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 6dd0ea8..d210123 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -127,7 +127,7 @@
 
 config PREFETCH
 	def_bool y
-	depends on PA8X00
+	depends on PA8X00 || PA7200
 
 config 64BIT
 	bool "64-bit kernel"
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index 6e79dbf..2d58b92 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -96,7 +96,7 @@
 	put_user(namlen, &dirent->d_namlen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
-	((char *) dirent) += reclen;
+	dirent = (void __user *)dirent + reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
 	return 0;
diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c
index d1833f1..1e64e7b 100644
--- a/arch/parisc/kernel/binfmt_elf32.c
+++ b/arch/parisc/kernel/binfmt_elf32.c
@@ -87,7 +87,7 @@
  */
 
 #define SET_PERSONALITY(ex, ibcs2) \
-	current->personality = PER_LINUX32; \
+	set_thread_flag(TIF_32BIT); \
 	current->thread.map_base = DEFAULT_MAP_BASE32; \
 	current->thread.task_size = DEFAULT_TASK_SIZE32 \
 
@@ -102,25 +102,3 @@
 }
 
 #include "../../../fs/binfmt_elf.c"
-
-/* Set up a separate execution domain for ELF32 binaries running
- * on an ELF64 kernel */
-
-static struct exec_domain parisc32_exec_domain = { 
-	.name = "Linux/ELF32",
-	.pers_low = PER_LINUX32,
-	.pers_high = PER_LINUX32,
-};      
-
-static int __init parisc32_exec_init(void)
-{
-	/* steal the identity signal mappings from the default domain */
-	parisc32_exec_domain.signal_map = default_exec_domain.signal_map;
-	parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
-
-	register_exec_domain(&parisc32_exec_domain);
-
-	return 0;
-}
-
-__initcall(parisc32_exec_init);
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index bc7c4a4..0be51e9 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -35,15 +35,12 @@
 EXPORT_SYMBOL(dcache_stride);
 
 
-#if defined(CONFIG_SMP)
 /* On some machines (e.g. ones with the Merced bus), there can be
  * only a single PxTLB broadcast at a time; this must be guaranteed
  * by software.  We put a spinlock around all TLB flushes  to
  * ensure this.
  */
 DEFINE_SPINLOCK(pa_tlb_lock);
-EXPORT_SYMBOL(pa_tlb_lock);
-#endif
 
 struct pdc_cache_info cache_info __read_mostly;
 #ifndef CONFIG_PA20
@@ -91,7 +88,8 @@
 
 		flush_kernel_dcache_page(page);
 		clear_bit(PG_dcache_dirty, &page->flags);
-	}
+	} else if (parisc_requires_coherency())
+		flush_kernel_dcache_page(page);
 }
 
 void
@@ -370,3 +368,45 @@
 
 	printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
 }
+
+extern void purge_kernel_dcache_page(unsigned long);
+extern void clear_user_page_asm(void *page, unsigned long vaddr);
+
+void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
+{
+	purge_kernel_dcache_page((unsigned long)page);
+	purge_tlb_start();
+	pdtlb_kernel(page);
+	purge_tlb_end();
+	clear_user_page_asm(page, vaddr);
+}
+EXPORT_SYMBOL(clear_user_page);
+
+void flush_kernel_dcache_page_addr(void *addr)
+{
+	flush_kernel_dcache_page_asm(addr);
+	purge_tlb_start();
+	pdtlb_kernel(addr);
+	purge_tlb_end();
+}
+EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+		    struct page *pg)
+{
+	/* no coherency needed (all in kmap/kunmap) */
+	copy_user_page_asm(vto, vfrom);
+	if (!parisc_requires_coherency())
+		flush_kernel_dcache_page_asm(vto);
+}
+EXPORT_SYMBOL(copy_user_page);
+
+#ifdef CONFIG_PA8X00
+
+void kunmap_parisc(void *addr)
+{
+	if (parisc_requires_coherency())
+		flush_kernel_dcache_page_addr(addr);
+}
+EXPORT_SYMBOL(kunmap_parisc);
+#endif
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 192357a..340b5e8 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -30,6 +30,7 @@
 
 
 #include <asm/psw.h>
+#include <asm/cache.h>		/* for L1_CACHE_SHIFT */
 #include <asm/assembly.h>	/* for LDREG/STREG defines */
 #include <asm/pgtable.h>
 #include <asm/signal.h>
@@ -478,11 +479,7 @@
 	bb,>=,n		\pmd,_PxD_PRESENT_BIT,\fault
 	DEP		%r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
 	copy		\pmd,%r9
-#ifdef CONFIG_64BIT
-	shld		%r9,PxD_VALUE_SHIFT,\pmd
-#else
-	shlw		%r9,PxD_VALUE_SHIFT,\pmd
-#endif
+	SHLREG		%r9,PxD_VALUE_SHIFT,\pmd
 	EXTR		\va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
 	DEP		%r0,31,PAGE_SHIFT,\pmd  /* clear offset */
 	shladd		\index,BITS_PER_PTE_ENTRY,\pmd,\pmd
@@ -970,11 +967,7 @@
 	/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
 	** irq_stat[] is defined using ____cacheline_aligned.
 	*/
-#ifdef CONFIG_64BIT
-	shld	%r1, 6, %r20
-#else
-	shlw	%r1, 5, %r20
-#endif
+	SHLREG	%r1,L1_CACHE_SHIFT,%r20
 	add     %r19,%r20,%r19	/* now have &irq_stat[smp_processor_id()] */
 #endif /* CONFIG_SMP */
 
@@ -1076,7 +1069,7 @@
 	BL	preempt_schedule_irq, %r2
 	nop
 
-	b	intr_restore		/* ssm PSW_SM_I done by intr_restore */
+	b,n	intr_restore		/* ssm PSW_SM_I done by intr_restore */
 #endif /* CONFIG_PREEMPT */
 
 	.import do_signal,code
@@ -2115,11 +2108,7 @@
 	ldw     TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
 
 	/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
-#ifdef CONFIG_64BIT
-	shld	%r26, 6, %r20
-#else
-	shlw	%r26, 5, %r20
-#endif
+	SHLREG	%r26,L1_CACHE_SHIFT,%r20
 	add     %r19,%r20,%r19	/* now have &irq_stat[smp_processor_id()] */
 #endif /* CONFIG_SMP */
 
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
index 3058bff..18ba4cb 100644
--- a/arch/parisc/kernel/hardware.c
+++ b/arch/parisc/kernel/hardware.c
@@ -231,6 +231,7 @@
 	{HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
 	{HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
 	{HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
+	{HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"},
 	{HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
 	{HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
 	{HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
@@ -584,8 +585,10 @@
 	{HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, 
 	{HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, 
 	{HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, 
+	{HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"},
 	{HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, 
 	{HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, 
+	{HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"},
 	{HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, 
 	{HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, 
 	{HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"}, 
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 3e79e62..eaad232 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -12,8 +12,6 @@
  * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
  */
 
-#include <linux/config.h>	/* for CONFIG_SMP */
-
 #include <asm/asm-offsets.h>
 #include <asm/psw.h>
 #include <asm/pdc.h>
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 5b8803c..9bdd019 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -45,6 +45,17 @@
 */
 static volatile unsigned long cpu_eiem = 0;
 
+/*
+** ack bitmap ... habitually set to 1, but reset to zero
+** between ->ack() and ->end() of the interrupt to prevent
+** re-interruption of a processing interrupt.
+*/
+static volatile unsigned long global_ack_eiem = ~0UL;
+/*
+** Local bitmap, same as above but for per-cpu interrupts
+*/
+static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
+
 static void cpu_disable_irq(unsigned int irq)
 {
 	unsigned long eirr_bit = EIEM_MASK(irq);
@@ -62,13 +73,6 @@
 
 	cpu_eiem |= eirr_bit;
 
-	/* FIXME: while our interrupts aren't nested, we cannot reset
-	 * the eiem mask if we're already in an interrupt.  Once we
-	 * implement nested interrupts, this can go away
-	 */
-	if (!in_interrupt())
-		set_eiem(cpu_eiem);
-
 	/* This is just a simple NOP IPI.  But what it does is cause
 	 * all the other CPUs to do a set_eiem(cpu_eiem) at the end
 	 * of the interrupt handler */
@@ -84,13 +88,45 @@
 void no_ack_irq(unsigned int irq) { }
 void no_end_irq(unsigned int irq) { }
 
+void cpu_ack_irq(unsigned int irq)
+{
+	unsigned long mask = EIEM_MASK(irq);
+	int cpu = smp_processor_id();
+
+	/* Clear in EIEM so we can no longer process */
+	if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
+		per_cpu(local_ack_eiem, cpu) &= ~mask;
+	else
+		global_ack_eiem &= ~mask;
+
+	/* disable the interrupt */
+	set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
+	/* and now ack it */
+	mtctl(mask, 23);
+}
+
+void cpu_end_irq(unsigned int irq)
+{
+	unsigned long mask = EIEM_MASK(irq);
+	int cpu = smp_processor_id();
+
+	/* set it in the eiems---it's no longer in process */
+	if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
+		per_cpu(local_ack_eiem, cpu) |= mask;
+	else
+		global_ack_eiem |= mask;
+
+	/* enable the interrupt */
+	set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
+}
+
 #ifdef CONFIG_SMP
 int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
 {
 	int cpu_dest;
 
 	/* timer and ipi have to always be received on all CPUs */
-	if (irq == TIMER_IRQ || irq == IPI_IRQ) {
+	if (CHECK_IRQ_PER_CPU(irq)) {
 		/* Bad linux design decision.  The mask has already
 		 * been set; we must reset it */
 		irq_desc[irq].affinity = CPU_MASK_ALL;
@@ -119,8 +155,8 @@
 	.shutdown	= cpu_disable_irq,
 	.enable		= cpu_enable_irq,
 	.disable	= cpu_disable_irq,
-	.ack		= no_ack_irq,
-	.end		= no_end_irq,
+	.ack		= cpu_ack_irq,
+	.end		= cpu_end_irq,
 #ifdef CONFIG_SMP
 	.set_affinity	= cpu_set_affinity_irq,
 #endif
@@ -209,7 +245,7 @@
 ** Then use that to get the Transaction address and data.
 */
 
-int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
+int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
 {
 	if (irq_desc[irq].action)
 		return -EBUSY;
@@ -298,82 +334,69 @@
 	return virt_irq - CPU_IRQ_BASE;
 }
 
+static inline int eirr_to_irq(unsigned long eirr)
+{
+#ifdef CONFIG_64BIT
+	int bit = fls64(eirr);
+#else
+	int bit = fls(eirr);
+#endif
+	return (BITS_PER_LONG - bit) + TIMER_IRQ;
+}
+
 /* ONLY called from entry.S:intr_extint() */
 void do_cpu_irq_mask(struct pt_regs *regs)
 {
 	unsigned long eirr_val;
+	int irq, cpu = smp_processor_id();
+#ifdef CONFIG_SMP
+	cpumask_t dest;
+#endif
 
+	local_irq_disable();
 	irq_enter();
 
-	/*
-	 * Don't allow TIMER or IPI nested interrupts.
-	 * Allowing any single interrupt to nest can lead to that CPU
-	 * handling interrupts with all enabled interrupts unmasked.
-	 */
-	set_eiem(0UL);
-
-	/* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
-	 * 2) We loop here on EIRR contents in order to avoid
-	 *    nested interrupts or having to take another interrupt
-	 *    when we could have just handled it right away.
-	 */
-	for (;;) {
-		unsigned long bit = (1UL << (BITS_PER_LONG - 1));
-		unsigned int irq;
-		eirr_val = mfctl(23) & cpu_eiem;
-		if (!eirr_val)
-			break;
-
-		mtctl(eirr_val, 23); /* reset bits we are going to process */
-
-		/* Work our way from MSb to LSb...same order we alloc EIRs */
-		for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
-#ifdef CONFIG_SMP
-			cpumask_t dest = irq_desc[irq].affinity;
-#endif
-			if (!(bit & eirr_val))
-				continue;
-
-			/* clear bit in mask - can exit loop sooner */
-			eirr_val &= ~bit;
+	eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem &
+		per_cpu(local_ack_eiem, cpu);
+	if (!eirr_val)
+		goto set_out;
+	irq = eirr_to_irq(eirr_val);
 
 #ifdef CONFIG_SMP
-			/* FIXME: because generic set affinity mucks
-			 * with the affinity before sending it to us
-			 * we can get the situation where the affinity is
-			 * wrong for our CPU type interrupts */
-			if (irq != TIMER_IRQ && irq != IPI_IRQ &&
-			    !cpu_isset(smp_processor_id(), dest)) {
-				int cpu = first_cpu(dest);
+	dest = irq_desc[irq].affinity;
+	if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
+	    !cpu_isset(smp_processor_id(), dest)) {
+		int cpu = first_cpu(dest);
 
-				printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
-				       irq, smp_processor_id(), cpu);
-				gsc_writel(irq + CPU_IRQ_BASE,
-					   cpu_data[cpu].hpa);
-				continue;
-			}
-#endif
-
-			__do_IRQ(irq, regs);
-		}
+		printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
+		       irq, smp_processor_id(), cpu);
+		gsc_writel(irq + CPU_IRQ_BASE,
+			   cpu_data[cpu].hpa);
+		goto set_out;
 	}
+#endif
+	__do_IRQ(irq, regs);
 
-	set_eiem(cpu_eiem);	/* restore original mask */
+ out:
 	irq_exit();
-}
+	return;
 
+ set_out:
+	set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
+	goto out;
+}
 
 static struct irqaction timer_action = {
 	.handler = timer_interrupt,
 	.name = "timer",
-	.flags = IRQF_DISABLED,
+	.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
 };
 
 #ifdef CONFIG_SMP
 static struct irqaction ipi_action = {
 	.handler = ipi_interrupt,
 	.name = "IPI",
-	.flags = IRQF_DISABLED,
+	.flags = IRQF_DISABLED | IRQF_PERCPU,
 };
 #endif
 
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
index 99d7fca..fb81e56 100644
--- a/arch/parisc/kernel/processor.c
+++ b/arch/parisc/kernel/processor.c
@@ -143,8 +143,9 @@
 	p = &cpu_data[cpuid];
 	boot_cpu_data.cpu_count++;
 
-	/* initialize counters */
-	memset(p, 0, sizeof(struct cpuinfo_parisc));
+	/* initialize counters - CPU 0 gets it_value set in time_init() */
+	if (cpuid)
+		memset(p, 0, sizeof(struct cpuinfo_parisc));
 
 	p->loops_per_jiffy = loops_per_jiffy;
 	p->dev = dev;		/* Save IODC data in case we need it */
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index bb83880..ee6653e 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -26,7 +26,6 @@
 #include <linux/stddef.h>
 #include <linux/compat.h>
 #include <linux/elf.h>
-#include <linux/personality.h>
 #include <asm/ucontext.h>
 #include <asm/rt_sigframe.h>
 #include <asm/uaccess.h>
@@ -433,13 +432,13 @@
 	if (in_syscall) {
 		regs->gr[31] = haddr;
 #ifdef __LP64__
-		if (personality(current->personality) == PER_LINUX)
+		if (!test_thread_flag(TIF_32BIT))
 			sigframe_size |= 1;
 #endif
 	} else {
 		unsigned long psw = USER_PSW;
 #ifdef __LP64__
-		if (personality(current->personality) == PER_LINUX)
+		if (!test_thread_flag(TIF_32BIT))
 			psw |= PSW_W;
 #endif
 
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 98e4095..faad338 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -262,6 +262,9 @@
 					this_cpu, which);
 				return IRQ_NONE;
 			} /* Switch */
+		/* let in any pending interrupts */
+		local_irq_enable();
+		local_irq_disable();
 		} /* while (ops) */
 	}
 	return IRQ_HANDLED;
@@ -430,8 +433,9 @@
 static void __init
 smp_cpu_init(int cpunum)
 {
-	extern int init_per_cpu(int);  /* arch/parisc/kernel/setup.c */
+	extern int init_per_cpu(int);  /* arch/parisc/kernel/processor.c */
 	extern void init_IRQ(void);    /* arch/parisc/kernel/irq.c */
+	extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */
 
 	/* Set modes and Enable floating point coprocessor */
 	(void) init_per_cpu(cpunum);
@@ -457,6 +461,7 @@
 	enter_lazy_tlb(&init_mm, current);
 
 	init_IRQ();   /* make sure no IRQ's are enabled or pending */
+	start_cpu_itimer();
 }
 
 
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 8b5df98..1db5588 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -31,6 +31,8 @@
 #include <linux/shm.h>
 #include <linux/smp_lock.h>
 #include <linux/syscalls.h>
+#include <linux/utsname.h>
+#include <linux/personality.h>
 
 int sys_pipe(int __user *fildes)
 {
@@ -248,3 +250,46 @@
 {
 	return -EINVAL;
 }
+
+long parisc_personality(unsigned long personality)
+{
+	long err;
+
+	if (personality(current->personality) == PER_LINUX32
+	    && personality == PER_LINUX)
+		personality = PER_LINUX32;
+
+	err = sys_personality(personality);
+	if (err == PER_LINUX32)
+		err = PER_LINUX;
+
+	return err;
+}
+
+static inline int override_machine(char __user *mach) {
+#ifdef CONFIG_COMPAT
+	if (personality(current->personality) == PER_LINUX32) {
+		if (__put_user(0, mach + 6) ||
+		    __put_user(0, mach + 7))
+			return -EFAULT;
+	}
+
+	return 0;
+#else /*!CONFIG_COMPAT*/
+	return 0;
+#endif /*CONFIG_COMPAT*/
+}
+
+long parisc_newuname(struct new_utsname __user *utsname)
+{
+	int err = 0;
+
+	down_read(&uts_sem);
+	if (copy_to_user(utsname, &system_utsname, sizeof(*utsname)))
+		err = -EFAULT;
+	up_read(&uts_sem);
+
+	err = override_machine(utsname->machine);
+
+	return (long)err;
+}
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 9670a89..a058004 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -6,7 +6,6 @@
  * thanks to Philipp Rumpf, Mike Shaver and various others
  * sorry about the wall, puffin..
  */
-#include <linux/config.h> /* for CONFIG_SMP */
 
 #include <asm/asm-offsets.h>
 #include <asm/unistd.h>
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index e27b432..701d66a 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -132,7 +132,7 @@
 	ENTRY_SAME(socketpair)
 	ENTRY_SAME(setpgid)
 	ENTRY_SAME(send)
-	ENTRY_SAME(newuname)
+	ENTRY_OURS(newuname)
 	ENTRY_SAME(umask)		/* 60 */
 	ENTRY_SAME(chroot)
 	ENTRY_SAME(ustat)
@@ -221,7 +221,7 @@
 	ENTRY_SAME(fchdir)
 	ENTRY_SAME(bdflush)
 	ENTRY_SAME(sysfs)		/* 135 */
-	ENTRY_SAME(personality)
+	ENTRY_OURS(personality)
 	ENTRY_SAME(ni_syscall)	/* for afs_syscall */
 	ENTRY_SAME(setfsuid)
 	ENTRY_SAME(setfsgid)
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index ab641d6..b3496b5 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -32,8 +32,7 @@
 
 #include <linux/timex.h>
 
-static long clocktick __read_mostly;	/* timer cycles per tick */
-static long halftick __read_mostly;
+static unsigned long clocktick __read_mostly;	/* timer cycles per tick */
 
 #ifdef CONFIG_SMP
 extern void smp_do_timer(struct pt_regs *regs);
@@ -41,46 +40,106 @@
 
 irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	long now;
-	long next_tick;
-	int nticks;
-	int cpu = smp_processor_id();
+	unsigned long now;
+	unsigned long next_tick;
+	unsigned long cycles_elapsed;
+	unsigned long cycles_remainder;
+	unsigned int cpu = smp_processor_id();
+
+	/* gcc can optimize for "read-only" case with a local clocktick */
+	unsigned long cpt = clocktick;
 
 	profile_tick(CPU_PROFILING, regs);
 
-	now = mfctl(16);
-	/* initialize next_tick to time at last clocktick */
+	/* Initialize next_tick to the expected tick time. */
 	next_tick = cpu_data[cpu].it_value;
 
-	/* since time passes between the interrupt and the mfctl()
-	 * above, it is never true that last_tick + clocktick == now.  If we
-	 * never miss a clocktick, we could set next_tick = last_tick + clocktick
-	 * but maybe we'll miss ticks, hence the loop.
-	 *
-	 * Variables are *signed*.
+	/* Get current interval timer.
+	 * CR16 reads as 64 bits in CPU wide mode.
+	 * CR16 reads as 32 bits in CPU narrow mode.
 	 */
+	now = mfctl(16);
 
-	nticks = 0;
-	while((next_tick - now) < halftick) {
-		next_tick += clocktick;
-		nticks++;
+	cycles_elapsed = now - next_tick;
+
+	if ((cycles_elapsed >> 5) < cpt) {
+		/* use "cheap" math (add/subtract) instead
+		 * of the more expensive div/mul method
+		 */
+		cycles_remainder = cycles_elapsed;
+		while (cycles_remainder > cpt) {
+			cycles_remainder -= cpt;
+		}
+	} else {
+		cycles_remainder = cycles_elapsed % cpt;
 	}
-	mtctl(next_tick, 16);
+
+	/* Can we differentiate between "early CR16" (aka Scenario 1) and
+	 * "long delay" (aka Scenario 3)? I don't think so.
+	 *
+	 * We expected timer_interrupt to be delivered at least a few hundred
+	 * cycles after the IT fires. But it's arbitrary how much time passes
+	 * before we call it "late". I've picked one second.
+	 */
+/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
+#if HZ == 1000
+	if (cycles_elapsed > (cpt << 10) )
+#elif HZ == 250
+	if (cycles_elapsed > (cpt << 8) )
+#elif HZ == 100
+	if (cycles_elapsed > (cpt << 7) )
+#else
+#warn WTF is HZ set to anyway?
+	if (cycles_elapsed > (HZ * cpt) )
+#endif
+	{
+		/* Scenario 3: very long delay?  bad in any case */
+		printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
+			" cycles %lX rem %lX "
+			" next/now %lX/%lX\n",
+			cpu,
+			cycles_elapsed, cycles_remainder,
+			next_tick, now );
+	}
+
+	/* convert from "division remainder" to "remainder of clock tick" */
+	cycles_remainder = cpt - cycles_remainder;
+
+	/* Determine when (in CR16 cycles) next IT interrupt will fire.
+	 * We want IT to fire modulo clocktick even if we miss/skip some.
+	 * But those interrupts don't in fact get delivered that regularly.
+	 */
+	next_tick = now + cycles_remainder;
+
 	cpu_data[cpu].it_value = next_tick;
 
-	while (nticks--) {
+	/* Skip one clocktick on purpose if we are likely to miss next_tick.
+	 * We want to avoid the new next_tick being less than CR16.
+	 * If that happened, itimer wouldn't fire until CR16 wrapped.
+	 * We'll catch the tick we missed on the tick after that.
+	 */
+	if (!(cycles_remainder >> 13))
+		next_tick += cpt;
+
+	/* Program the IT when to deliver the next interrupt. */
+        /* Only bottom 32-bits of next_tick are written to cr16.  */
+	mtctl(next_tick, 16);
+
+
+	/* Done mucking with unreliable delivery of interrupts.
+	 * Go do system house keeping.
+	 */
 #ifdef CONFIG_SMP
-		smp_do_timer(regs);
+	smp_do_timer(regs);
 #else
-		update_process_times(user_mode(regs));
+	update_process_times(user_mode(regs));
 #endif
-		if (cpu == 0) {
-			write_seqlock(&xtime_lock);
-			do_timer(1);
-			write_sequnlock(&xtime_lock);
-		}
+	if (cpu == 0) {
+		write_seqlock(&xtime_lock);
+		do_timer(regs);
+		write_sequnlock(&xtime_lock);
 	}
-    
+
 	/* check soft power switch status */
 	if (cpu == 0 && !atomic_read(&power_tasklet.count))
 		tasklet_schedule(&power_tasklet);
@@ -106,14 +165,12 @@
 EXPORT_SYMBOL(profile_pc);
 
 
-/*** converted from ia64 ***/
 /*
  * Return the number of micro-seconds that elapsed since the last
  * update to wall time (aka xtime).  The xtime_lock
  * must be at least read-locked when calling this routine.
  */
-static inline unsigned long
-gettimeoffset (void)
+static inline unsigned long gettimeoffset (void)
 {
 #ifndef CONFIG_SMP
 	/*
@@ -121,21 +178,44 @@
 	 *    Once parisc-linux learns the cr16 difference between processors,
 	 *    this could be made to work.
 	 */
-	long last_tick;
-	long elapsed_cycles;
+	unsigned long now;
+	unsigned long prev_tick;
+	unsigned long next_tick;
+	unsigned long elapsed_cycles;
+	unsigned long usec;
+	unsigned long cpuid = smp_processor_id();
+	unsigned long cpt = clocktick;
 
-	/* it_value is the intended time of the next tick */
-	last_tick = cpu_data[smp_processor_id()].it_value;
+	next_tick = cpu_data[cpuid].it_value;
+	now = mfctl(16);	/* Read the hardware interval timer.  */
 
-	/* Subtract one tick and account for possible difference between
-	 * when we expected the tick and when it actually arrived.
-	 * (aka wall vs real)
-	 */
-	last_tick -= clocktick * (jiffies - wall_jiffies + 1);
-	elapsed_cycles = mfctl(16) - last_tick;
+	prev_tick = next_tick - cpt;
 
-	/* the precision of this math could be improved */
-	return elapsed_cycles / (PAGE0->mem_10msec / 10000);
+	/* Assume Scenario 1: "now" is later than prev_tick.  */
+	elapsed_cycles = now - prev_tick;
+
+/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
+#if HZ == 1000
+	if (elapsed_cycles > (cpt << 10) )
+#elif HZ == 250
+	if (elapsed_cycles > (cpt << 8) )
+#elif HZ == 100
+	if (elapsed_cycles > (cpt << 7) )
+#else
+#warn WTF is HZ set to anyway?
+	if (elapsed_cycles > (HZ * cpt) )
+#endif
+	{
+		/* Scenario 3: clock ticks are missing. */
+		printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!"
+			" cycles %lX prev/now/next %lX/%lX/%lX  clock %lX\n",
+			cpuid, elapsed_cycles / cpt,
+			elapsed_cycles, prev_tick, now, next_tick, cpt);
+	}
+
+	/* FIXME: Can we improve the precision? Not with PAGE0. */
+	usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec;
+	return usec;
 #else
 	return 0;
 #endif
@@ -146,6 +226,7 @@
 {
 	unsigned long flags, seq, usec, sec;
 
+	/* Hold xtime_lock and adjust timeval.  */
 	do {
 		seq = read_seqbegin_irqsave(&xtime_lock, flags);
 		usec = gettimeoffset();
@@ -153,25 +234,13 @@
 		usec += (xtime.tv_nsec / 1000);
 	} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
 
-	if (unlikely(usec > LONG_MAX)) {
-		/* This can happen if the gettimeoffset adjustment is
-		 * negative and xtime.tv_nsec is smaller than the
-		 * adjustment */
-		printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
-		usec += USEC_PER_SEC;
-		--sec;
-		/* This should never happen, it means the negative
-		 * time adjustment was more than a second, so there's
-		 * something seriously wrong */
-		BUG_ON(usec > LONG_MAX);
-	}
-
-
+	/* Move adjusted usec's into sec's.  */
 	while (usec >= USEC_PER_SEC) {
 		usec -= USEC_PER_SEC;
 		++sec;
 	}
 
+	/* Return adjusted result.  */
 	tv->tv_sec = sec;
 	tv->tv_usec = usec;
 }
@@ -223,22 +292,23 @@
 }
 
 
+void __init start_cpu_itimer(void)
+{
+	unsigned int cpu = smp_processor_id();
+	unsigned long next_tick = mfctl(16) + clocktick;
+
+	mtctl(next_tick, 16);		/* kick off Interval Timer (CR16) */
+
+	cpu_data[cpu].it_value = next_tick;
+}
+
 void __init time_init(void)
 {
-	unsigned long next_tick;
 	static struct pdc_tod tod_data;
 
 	clocktick = (100 * PAGE0->mem_10msec) / HZ;
-	halftick = clocktick / 2;
 
-	/* Setup clock interrupt timing */
-
-	next_tick = mfctl(16);
-	next_tick += clocktick;
-	cpu_data[smp_processor_id()].it_value = next_tick;
-
-	/* kick off Itimer (CR16) */
-	mtctl(next_tick, 16);
+	start_cpu_itimer();	/* get CPU 0 started */
 
 	if(pdc_tod_read(&tod_data) == 0) {
 		write_seqlock_irq(&xtime_lock);
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 77b28cb..65cd6ca 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -16,6 +16,7 @@
 #include <linux/errno.h>
 #include <linux/ptrace.h>
 #include <linux/timer.h>
+#include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/smp.h>
@@ -245,6 +246,15 @@
 		current->comm, current->pid, str, err);
 	show_regs(regs);
 
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+
+	if (panic_on_oops) {
+		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+		ssleep(5);
+		panic("Fatal exception");
+	}
+
 	/* Wot's wrong wif bein' racy? */
 	if (current->thread.flags & PARISC_KERNEL_DEATH) {
 		printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 25ad28d..0667f2b 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -31,10 +31,7 @@
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
-extern char _text;	/* start of kernel code, defined by linker */
 extern int  data_start;
-extern char _end;	/* end of BSS, defined by linker */
-extern char __init_begin, __init_end;
 
 #ifdef CONFIG_DISCONTIGMEM
 struct node_map_data node_data[MAX_NUMNODES] __read_mostly;
@@ -319,8 +316,8 @@
 
 	reserve_bootmem_node(NODE_DATA(0), 0UL,
 			(unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
-	reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
-			(unsigned long)(&_end - &_text));
+	reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
+			(unsigned long)(_end - _text));
 	reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
 			((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
 
@@ -355,8 +352,8 @@
 #endif
 
 	data_resource.start =  virt_to_phys(&data_start);
-	data_resource.end = virt_to_phys(&_end)-1;
-	code_resource.start = virt_to_phys(&_text);
+	data_resource.end = virt_to_phys(_end) - 1;
+	code_resource.start = virt_to_phys(_text);
 	code_resource.end = virt_to_phys(&data_start)-1;
 
 	/* We don't know which region the kernel will be in, so try
@@ -385,12 +382,12 @@
 	 */
 	local_irq_disable();
 
-	memset(&__init_begin, 0x00, 
-		(unsigned long)&__init_end - (unsigned long)&__init_begin);
+	memset(__init_begin, 0x00,
+		(unsigned long)__init_end - (unsigned long)__init_begin);
 
 	flush_data_cache();
 	asm volatile("sync" : : );
-	flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
+	flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end);
 	asm volatile("sync" : : );
 
 	local_irq_enable();
@@ -398,8 +395,8 @@
 	
 	/* align __init_begin and __init_end to page size,
 	   ignoring linker script where we might have tried to save RAM */
-	init_begin = PAGE_ALIGN((unsigned long)(&__init_begin));
-	init_end   = PAGE_ALIGN((unsigned long)(&__init_end));
+	init_begin = PAGE_ALIGN((unsigned long)(__init_begin));
+	init_end   = PAGE_ALIGN((unsigned long)(__init_end));
 	for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
 		ClearPageReserved(virt_to_page(addr));
 		init_page_count(virt_to_page(addr));
@@ -578,7 +575,7 @@
 	extern const unsigned long fault_vector_20;
 	extern void * const linux_gateway_page;
 
-	ro_start = __pa((unsigned long)&_text);
+	ro_start = __pa((unsigned long)_text);
 	ro_end   = __pa((unsigned long)&data_start);
 	fv_addr  = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
 	gw_addr  = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
index 2738456..47a1d2a 100644
--- a/arch/parisc/mm/ioremap.c
+++ b/arch/parisc/mm/ioremap.c
@@ -188,7 +188,7 @@
 }
 EXPORT_SYMBOL(__ioremap);
 
-void iounmap(void __iomem *addr)
+void iounmap(const volatile void __iomem *addr)
 {
 	if (addr > high_memory)
 		return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 96ef656..8b69104 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -338,10 +338,6 @@
 	  RS/6000 machine, an Apple machine, or a PReP, CHRP,
 	  Maple or Cell-based machine.
 
-config PPC_ISERIES
-	bool "IBM Legacy iSeries"
-	depends on PPC64
-
 config EMBEDDED6xx
 	bool "Embedded 6xx/7xx/7xxx-based board"
 	depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
@@ -355,6 +351,16 @@
 	  <http://linux-apus.sourceforge.net/>.
 endchoice
 
+config QUICC_ENGINE
+	bool
+	depends on PPC_MPC836x || PPC_MPC832x
+	default y
+	help
+	  The QUICC Engine (QE) is a new generation of communications
+	  coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
+	  Selecting this option means that you wish to build a kernel
+	  for a machine with a QE coprocessor.
+
 config PPC_PSERIES
 	depends on PPC_MULTIPLATFORM && PPC64
 	bool "IBM pSeries & new (POWER5-based) iSeries"
@@ -365,6 +371,10 @@
 	select PPC_UDBG_16550
 	default y
 
+config PPC_ISERIES
+	bool "IBM Legacy iSeries"
+	depends on PPC_MULTIPLATFORM && PPC64
+
 config PPC_CHRP
 	bool "Common Hardware Reference Platform (CHRP) based machines"
 	depends on PPC_MULTIPLATFORM && PPC32
@@ -594,6 +604,7 @@
 
 source arch/powerpc/platforms/embedded6xx/Kconfig
 source arch/powerpc/platforms/4xx/Kconfig
+source arch/powerpc/platforms/82xx/Kconfig
 source arch/powerpc/platforms/83xx/Kconfig
 source arch/powerpc/platforms/85xx/Kconfig
 source arch/powerpc/platforms/86xx/Kconfig
@@ -1058,6 +1069,8 @@
 
 # XXX source "arch/ppc/8260_io/Kconfig"
 
+source "arch/powerpc/sysdev/qe_lib/Kconfig"
+
 source "arch/powerpc/platforms/iseries/Kconfig"
 
 source "lib/Kconfig"
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index c383d56..003520b 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -113,7 +113,7 @@
 endif
 
 quiet_cmd_wrap	= WRAP    $@
-      cmd_wrap	=$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
+      cmd_wrap	=$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
 quiet_cmd_wrap_initrd = WRAP    $@
       cmd_wrap_initrd =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
 				-i $(obj)/ramdisk.image.gz vmlinux
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
new file mode 100644
index 0000000..34efdd0
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -0,0 +1,223 @@
+/*
+ * MPC8272 ADS Device Tree Source
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+/ {
+       model = "MPC8272ADS";
+       compatible = "MPC8260ADS";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       linux,phandle = <100>;
+
+       cpus {
+               #cpus = <1>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               linux,phandle = <200>;
+
+               PowerPC,8272@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       d-cache-line-size = <20>;       // 32 bytes
+                       i-cache-line-size = <20>;       // 32 bytes
+                       d-cache-size = <4000>;          // L1, 16K
+                       i-cache-size = <4000>;          // L1, 16K
+                       timebase-frequency = <0>;
+                       bus-frequency = <0>;
+                       clock-frequency = <0>;
+                       32-bit;
+                       linux,phandle = <201>;
+                       linux,boot-cpu;
+               };
+       };
+
+       interrupt-controller@f8200000 {
+               linux,phandle = <f8200000>;
+               #address-cells = <0>;
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               reg = <f8200000 f8200004>;
+               built-in;
+               device_type = "pci-pic";
+       };
+       memory {
+               device_type = "memory";
+               linux,phandle = <300>;
+               reg = <00000000 4000000 f4500000 00000020>;
+       };
+
+       soc8272@f0000000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               #interrupt-cells = <2>;
+               device_type = "soc";
+               ranges = < 0 0 2 00000000 f0000000 00053000>;
+               reg = <f0000000 0>;
+
+               mdio@0 {
+                       device_type = "mdio";
+                       compatible = "fs_enet";
+                       reg = <0 0>;
+                       linux,phandle = <24520>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       ethernet-phy@0 {
+                               linux,phandle = <2452000>;
+                               interrupt-parent = <10c00>;
+                               interrupts = <19 1>;
+                               reg = <0>;
+                               bitbang = [ 12 12 13 02 02 01 ];
+                               device_type = "ethernet-phy";
+                       };
+                       ethernet-phy@1 {
+                               linux,phandle = <2452001>;
+                               interrupt-parent = <10c00>;
+                               interrupts = <19 1>;
+                               bitbang = [ 12 12 13 02 02 01 ];
+                               reg = <3>;
+                               device_type = "ethernet-phy";
+                       };
+               };
+
+               ethernet@24000 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       device_type = "network";
+                       device-id = <2>;
+                       compatible = "fs_enet";
+                       model = "FCC";
+                       reg = <11300 20 8400 100 11380 30>;
+                       mac-address = [ 00 11 2F 99 43 54 ];
+                       interrupts = <20 2>;
+                       interrupt-parent = <10c00>;
+                       phy-handle = <2452000>;
+                       rx-clock = <13>;
+                       tx-clock = <12>;
+               };
+
+               ethernet@25000 {
+                       device_type = "network";
+                       device-id = <3>;
+                       compatible = "fs_enet";
+                       model = "FCC";
+                       reg = <11320 20 8500 100 113b0 30>;
+                       mac-address = [ 00 11 2F 99 44 54 ];
+                       interrupts = <21 2>;
+                       interrupt-parent = <10c00>;
+                       phy-handle = <2452001>;
+                       rx-clock = <17>;
+                       tx-clock = <18>;
+               };
+
+               cpm@f0000000 {
+                       linux,phandle = <f0000000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       #interrupt-cells = <2>;
+                       device_type = "cpm";
+                       model = "CPM2";
+                       ranges = <00000000 00000000 3ffff>;
+                       reg = <10d80 3280>;
+                       command-proc = <119c0>;
+                       brg-frequency = <17D7840>;
+                       cpm_clk = <BEBC200>;
+
+                       scc@11a00 {
+                               device_type = "serial";
+                               compatible = "cpm_uart";
+                               model = "SCC";
+                               device-id = <2>;
+                               reg = <11a00 20 8000 100>;
+                               current-speed = <1c200>;
+                               interrupts = <28 2>;
+                               interrupt-parent = <10c00>;
+                               clock-setup = <0 00ffffff>;
+                               rx-clock = <1>;
+                               tx-clock = <1>;
+                       };
+
+                       scc@11a60 {
+                               device_type = "serial";
+                               compatible = "cpm_uart";
+                               model = "SCC";
+                               device-id = <5>;
+                               reg = <11a60 20 8300 100>;
+                               current-speed = <1c200>;
+                               interrupts = <2b 2>;
+                               interrupt-parent = <10c00>;
+                               clock-setup = <1b ffffff00>;
+                               rx-clock = <4>;
+                               tx-clock = <4>;
+                       };
+
+               };
+               interrupt-controller@10c00 {
+                       linux,phandle = <10c00>;
+                       #address-cells = <0>;
+                       #interrupt-cells = <2>;
+                       interrupt-controller;
+                       reg = <10c00 80>;
+                       built-in;
+                       device_type = "cpm-pic";
+		       compatible = "CPM2";
+               };
+               pci@0500 {
+                       linux,phandle = <0500>;
+                       #interrupt-cells = <1>;
+                       #size-cells = <2>;
+                       #address-cells = <3>;
+                       compatible = "8272";
+                       device_type = "pci";
+                       reg = <10430 4dc>;
+                       clock-frequency = <3f940aa>;
+                       interrupt-map-mask = <f800 0 0 7>;
+                       interrupt-map = <
+
+                                       /* IDSEL 0x16 */
+                                        b000 0 0 1 f8200000 40 0
+                                        b000 0 0 2 f8200000 41 0
+                                        b000 0 0 3 f8200000 42 0
+                                        b000 0 0 4 f8200000 43 0
+
+                                       /* IDSEL 0x17 */
+                                        b800 0 0 1 f8200000 43 0
+                                        b800 0 0 2 f8200000 40 0
+                                        b800 0 0 3 f8200000 41 0
+                                        b800 0 0 4 f8200000 42 0
+
+                                       /* IDSEL 0x18 */
+                                        c000 0 0 1 f8200000 42 0
+                                        c000 0 0 2 f8200000 43 0
+                                        c000 0 0 3 f8200000 40 0
+                                        c000 0 0 4 f8200000 41 0>;
+                       interrupt-parent = <10c00>;
+                       interrupts = <14 3>;
+                       bus-range = <0 0>;
+                       ranges = <02000000 0 80000000 80000000 0 40000000
+                                 01000000 0 00000000 f6000000 0 02000000>;
+               };
+
+/* May need to remove if on a part without crypto engine */
+               crypto@30000 {
+                       device_type = "crypto";
+                       model = "SEC2";
+                       compatible = "talitos";
+                       reg = <30000 10000>;
+                       interrupts = <b 0>;
+                       interrupt-parent = <10c00>;
+                       num-channels = <4>;
+                       channel-fifo-len = <18>;
+                       exec-units-mask = <0000007e>;
+/* desc mask is for rev1.x, we need runtime fixup for >=2.x */
+                       descriptor-types-mask = <01010ebf>;
+               };
+
+       };
+};
diff --git a/arch/powerpc/boot/dts/mpc8360emds.dts b/arch/powerpc/boot/dts/mpc8360emds.dts
new file mode 100644
index 0000000..9022192
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8360emds.dts
@@ -0,0 +1,375 @@
+/*
+ * MPC8360E EMDS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+/*
+/memreserve/	00000000 1000000;
+*/
+
+/ {
+	model = "MPC8360EPB";
+	compatible = "MPC83xx";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	linux,phandle = <100>;
+
+	cpus {
+		#cpus = <1>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		linux,phandle = <200>;
+
+		PowerPC,8360@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <20>;	// 32 bytes
+			i-cache-line-size = <20>;	// 32 bytes
+			d-cache-size = <8000>;		// L1, 32K
+			i-cache-size = <8000>;		// L1, 32K
+			timebase-frequency = <3EF1480>;
+			bus-frequency = <FBC5200>;
+			clock-frequency = <1F78A400>;
+			32-bit;
+			linux,phandle = <201>;
+			linux,boot-cpu;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		linux,phandle = <300>;
+		reg = <00000000 10000000>;
+	};
+
+	bcsr@f8000000 {
+		device_type = "board-control";
+		reg = <f8000000 8000>;
+	};
+
+	soc8360@e0000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		device_type = "soc";
+		ranges = <0 e0000000 00100000>;
+		reg = <e0000000 00000200>;
+		bus-frequency = <FBC5200>;
+
+		wdt@200 {
+			device_type = "watchdog";
+			compatible = "mpc83xx_wdt";
+			reg = <200 100>;
+		};
+
+		i2c@3000 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3000 100>;
+			interrupts = <e 8>;
+			interrupt-parent = <700>;
+			dfsrr;
+		};
+
+		i2c@3100 {
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <3100 100>;
+			interrupts = <f 8>;
+			interrupt-parent = <700>;
+			dfsrr;
+		};
+
+		serial@4500 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4500 100>;
+			clock-frequency = <FBC5200>;
+			interrupts = <9 8>;
+			interrupt-parent = <700>;
+		};
+
+		serial@4600 {
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <4600 100>;
+			clock-frequency = <FBC5200>;
+			interrupts = <a 8>;
+			interrupt-parent = <700>;
+		};
+
+		crypto@30000 {
+			device_type = "crypto";
+			model = "SEC2";
+			compatible = "talitos";
+			reg = <30000 10000>;
+			interrupts = <b 8>;
+			interrupt-parent = <700>;
+			num-channels = <4>;
+			channel-fifo-len = <18>;
+			exec-units-mask = <0000007e>;
+			/* desc mask is for rev1.x, we need runtime fixup for >=2.x */
+			descriptor-types-mask = <01010ebf>;
+		};
+
+		pci@8500 {
+			linux,phandle = <8500>;
+			interrupt-map-mask = <f800 0 0 7>;
+			interrupt-map = <
+
+					/* IDSEL 0x11 AD17 */
+					 8800 0 0 1 700 14 8
+					 8800 0 0 2 700 15 8
+					 8800 0 0 3 700 16 8
+					 8800 0 0 4 700 17 8
+
+					/* IDSEL 0x12 AD18 */
+					 9000 0 0 1 700 16 8
+					 9000 0 0 2 700 17 8
+					 9000 0 0 3 700 14 8
+					 9000 0 0 4 700 15 8
+
+					/* IDSEL 0x13 AD19 */
+					 9800 0 0 1 700 17 8
+					 9800 0 0 2 700 14 8
+					 9800 0 0 3 700 15 8
+					 9800 0 0 4 700 16 8
+
+					/* IDSEL 0x15 AD21*/
+					 a800 0 0 1 700 14 8
+					 a800 0 0 2 700 15 8
+					 a800 0 0 3 700 16 8
+					 a800 0 0 4 700 17 8
+
+					/* IDSEL 0x16 AD22*/
+					 b000 0 0 1 700 17 8
+					 b000 0 0 2 700 14 8
+					 b000 0 0 3 700 15 8
+					 b000 0 0 4 700 16 8
+
+					/* IDSEL 0x17 AD23*/
+					 b800 0 0 1 700 16 8
+					 b800 0 0 2 700 17 8
+					 b800 0 0 3 700 14 8
+					 b800 0 0 4 700 15 8
+
+					/* IDSEL 0x18 AD24*/
+					 c000 0 0 1 700 15 8
+					 c000 0 0 2 700 16 8
+					 c000 0 0 3 700 17 8
+					 c000 0 0 4 700 14 8>;
+			interrupt-parent = <700>;
+			interrupts = <42 8>;
+			bus-range = <0 0>;
+			ranges = <02000000 0 a0000000 a0000000 0 10000000
+				  42000000 0 80000000 80000000 0 10000000
+				  01000000 0 00000000 e2000000 0 00100000>;
+			clock-frequency = <3f940aa>;
+			#interrupt-cells = <1>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			reg = <8500 100>;
+			compatible = "83xx";
+			device_type = "pci";
+		};
+
+		pic@700 {
+			linux,phandle = <700>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <700 100>;
+			built-in;
+			device_type = "ipic";
+		};
+
+		par_io@1400 {
+			reg = <1400 100>;
+			device_type = "par_io";
+			num-ports = <7>;
+
+			ucc_pin@01 {
+				linux,phandle = <140001>;
+				pio-map = <
+			/* port  pin  dir  open_drain  assignment  has_irq */
+					0  3  1  0  1  0 	/* TxD0 */
+					0  4  1  0  1  0 	/* TxD1 */
+					0  5  1  0  1  0 	/* TxD2 */
+					0  6  1  0  1  0 	/* TxD3 */
+					1  6  1  0  3  0 	/* TxD4 */
+					1  7  1  0  1  0 	/* TxD5 */
+					1  9  1  0  2  0 	/* TxD6 */
+					1  a  1  0  2  0 	/* TxD7 */
+					0  9  2  0  1  0 	/* RxD0 */
+					0  a  2  0  1  0 	/* RxD1 */
+					0  b  2  0  1  0 	/* RxD2 */
+					0  c  2  0  1  0 	/* RxD3 */
+					0  d  2  0  1  0 	/* RxD4 */
+					1  1  2  0  2  0 	/* RxD5 */
+					1  0  2  0  2  0 	/* RxD6 */
+					1  4  2  0  2  0 	/* RxD7 */
+					0  7  1  0  1  0 	/* TX_EN */
+					0  8  1  0  1  0 	/* TX_ER */
+					0  f  2  0  1  0 	/* RX_DV */
+					0  10 2  0  1  0 	/* RX_ER */
+					0  0  2  0  1  0 	/* RX_CLK */
+					2  9  1  0  3  0 	/* GTX_CLK - CLK10 */
+					2  8  2  0  1  0>;	/* GTX125 - CLK9 */
+			};
+			ucc_pin@02 {
+				linux,phandle = <140002>;
+				pio-map = <
+			/* port  pin  dir  open_drain  assignment  has_irq */
+					0  11 1  0  1  0   /* TxD0 */
+					0  12 1  0  1  0   /* TxD1 */
+					0  13 1  0  1  0   /* TxD2 */
+					0  14 1  0  1  0   /* TxD3 */
+					1  2  1  0  1  0   /* TxD4 */
+					1  3  1  0  2  0   /* TxD5 */
+					1  5  1  0  3  0   /* TxD6 */
+					1  8  1  0  3  0   /* TxD7 */
+					0  17 2  0  1  0   /* RxD0 */
+					0  18 2  0  1  0   /* RxD1 */
+					0  19 2  0  1  0   /* RxD2 */
+					0  1a 2  0  1  0   /* RxD3 */
+					0  1b 2  0  1  0   /* RxD4 */
+					1  c  2  0  2  0   /* RxD5 */
+					1  d  2  0  3  0   /* RxD6 */
+					1  b  2  0  2  0   /* RxD7 */
+					0  15 1  0  1  0   /* TX_EN */
+					0  16 1  0  1  0   /* TX_ER */
+					0  1d 2  0  1  0   /* RX_DV */
+					0  1e 2  0  1  0   /* RX_ER */
+					0  1f 2  0  1  0   /* RX_CLK */
+					2  2  1  0  2  0   /* GTX_CLK - CLK10 */
+					2  3  2  0  1  0   /* GTX125 - CLK4 */
+					0  1  3  0  2  0   /* MDIO */
+					0  2  1  0  1  0>; /* MDC */
+			};
+
+		};
+	};
+
+	qe@e0100000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "qe";
+		model = "QE";
+		ranges = <0 e0100000 00100000>;
+		reg = <e0100000 480>;
+		brg-frequency = <0>;
+		bus-frequency = <179A7B00>;
+
+		muram@10000 {
+			device_type = "muram";
+			ranges = <0 00010000 0000c000>;
+
+			data-only@0{
+				reg = <0 c000>;
+			};
+		};
+
+		spi@4c0 {
+			device_type = "spi";
+			compatible = "fsl_spi";
+			reg = <4c0 40>;
+			interrupts = <2>;
+			interrupt-parent = <80>;
+			mode = "cpu";
+		};
+
+		spi@500 {
+			device_type = "spi";
+			compatible = "fsl_spi";
+			reg = <500 40>;
+			interrupts = <1>;
+			interrupt-parent = <80>;
+			mode = "cpu";
+		};
+
+		usb@6c0 {
+			device_type = "usb";
+			compatible = "qe_udc";
+			reg = <6c0 40 8B00 100>;
+			interrupts = <b>;
+			interrupt-parent = <80>;
+			mode = "slave";
+		};
+
+		ucc@2000 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			model = "UCC";
+			device-id = <1>;
+			reg = <2000 200>;
+			interrupts = <20>;
+			interrupt-parent = <80>;
+			mac-address = [ 00 04 9f 00 23 23 ];
+			rx-clock = <0>;
+			tx-clock = <19>;
+			phy-handle = <212000>;
+			pio-handle = <140001>;
+		};
+
+		ucc@3000 {
+			device_type = "network";
+			compatible = "ucc_geth";
+			model = "UCC";
+			device-id = <2>;
+			reg = <3000 200>;
+			interrupts = <21>;
+			interrupt-parent = <80>;
+			mac-address = [ 00 11 22 33 44 55 ];
+			rx-clock = <0>;
+			tx-clock = <14>;
+			phy-handle = <212001>;
+			pio-handle = <140002>;
+		};
+
+		mdio@2120 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <2120 18>;
+			device_type = "mdio";
+			compatible = "ucc_geth_phy";
+
+			ethernet-phy@00 {
+				linux,phandle = <212000>;
+				interrupt-parent = <700>;
+				interrupts = <11 2>;
+				reg = <0>;
+				device_type = "ethernet-phy";
+				interface = <6>; //ENET_1000_GMII
+			};
+			ethernet-phy@01 {
+				linux,phandle = <212001>;
+				interrupt-parent = <700>;
+				interrupts = <12 2>;
+				reg = <1>;
+				device_type = "ethernet-phy";
+				interface = <6>;
+			};
+		};
+
+		qeic@80 {
+			linux,phandle = <80>;
+			interrupt-controller;
+			device_type = "qeic";
+			#address-cells = <0>;
+			#interrupt-cells = <1>;
+			reg = <80 80>;
+			built-in;
+			big-endian;
+			interrupts = <20 8 21 8>; //high:32 low:33
+			interrupt-parent = <700>;
+		};
+
+	};
+};
diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S
index 6016251..05f3238 100644
--- a/arch/powerpc/boot/zImage.coff.lds.S
+++ b/arch/powerpc/boot/zImage.coff.lds.S
@@ -15,6 +15,7 @@
   {
     *(.rodata*)
     *(.data*)
+    *(__builtin_*)
     *(.sdata*)
     __got2_start = .;
     *(.got2)
diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig
new file mode 100644
index 0000000..c070341
--- /dev/null
+++ b/arch/powerpc/configs/mpc8360emds_defconfig
@@ -0,0 +1,1018 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18
+# Thu Sep 21 18:14:27 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+CONFIG_PPC_83xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_QUICC_ENGINE=y
+CONFIG_PPC_GEN550=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_MPC834x_ITX is not set
+CONFIG_MPC8360E_PB=y
+CONFIG_PPC_MPC836x=y
+# CONFIG_MPIC is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+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_ARPD 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_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR 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_COW_COMMON 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_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+# CONFIG_BLK_DEV_SD is not set
+# 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_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transport Attributes
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX 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_DPT_I2O is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA 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 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC 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
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB 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_CASSINI 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_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_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_GIANFAR is not set
+CONFIG_UCC_GETH=y
+# CONFIG_UGETH_NAPI is not set
+# CONFIG_UGETH_MAGIC_PACKET is not set
+# CONFIG_UGETH_FILTERING is not set
+# CONFIG_UGETH_TX_ON_DEMOND is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER 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 is not set
+# 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 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
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# 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_83xx_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_HW_RANDOM=y
+# 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_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 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_PIIX4 is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 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
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 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_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP 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_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_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_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# 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_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 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
+# CONFIG_9P_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 is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# QE Options
+#
+# CONFIG_UCC_SLOW is not set
+CONFIG_UCC_FAST=y
+CONFIG_UCC=y
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+
+#
+# Instrumentation Support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY 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=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 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_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 190a57e..47a613c 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -763,10 +763,10 @@
 		.cpu_setup		= __setup_cpu_603,
 		.platform		= "ppc603",
 	},
-	{	/* e300 (a 603e core, plus some) on 83xx */
+	{	/* e300c1 (a 603e core, plus some) on 83xx */
 		.pvr_mask		= 0x7fff0000,
 		.pvr_value		= 0x00830000,
-		.cpu_name		= "e300",
+		.cpu_name		= "e300c1",
 		.cpu_features		= CPU_FTRS_E300,
 		.cpu_user_features	= COMMON_USER,
 		.icache_bsize		= 32,
@@ -774,6 +774,17 @@
 		.cpu_setup		= __setup_cpu_603,
 		.platform		= "ppc603",
 	},
+	{	/* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */
+		.pvr_mask		= 0x7fff0000,
+		.pvr_value		= 0x00840000,
+		.cpu_name		= "e300c2",
+		.cpu_features		= CPU_FTRS_E300,
+		.cpu_user_features	= PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+		.icache_bsize		= 32,
+		.dcache_bsize		= 32,
+		.cpu_setup		= __setup_cpu_603,
+		.platform		= "ppc603",
+	},
 	{	/* default match, we assume split I/D cache & TB (non-601)... */
 		.pvr_mask		= 0x00000000,
 		.pvr_value		= 0x00000000,
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 2cd872b..748e74f 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -27,10 +27,7 @@
 #include <asm/ppc_asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/cputable.h>
-
-#ifdef CONFIG_PPC_ISERIES
-#define DO_SOFT_DISABLE
-#endif
+#include <asm/firmware.h>
 
 /*
  * System calls.
@@ -91,6 +88,7 @@
 	ld	r11,exception_marker@toc(r2)
 	std	r11,-16(r9)		/* "regshere" marker */
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
 	/* Hack for handling interrupts when soft-enabling on iSeries */
 	cmpdi	cr1,r0,0x5555		/* syscall 0x5555 */
 	andi.	r10,r12,MSR_PR		/* from kernel */
@@ -98,6 +96,7 @@
 	beq	hardware_interrupt_entry
 	lbz	r10,PACAPROCENABLED(r13)
 	std	r10,SOFTE(r1)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
 	mfmsr	r11
 	ori	r11,r11,MSR_EE
@@ -462,6 +461,7 @@
 
 restore:
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
 	ld	r5,SOFTE(r1)
 	cmpdi	0,r5,0
 	beq	4f
@@ -480,6 +480,7 @@
 	b	.ret_from_except_lite		/* loop back and handle more */
 
 4:	stb	r5,PACAPROCENABLED(r13)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
 
 	ld	r3,_MSR(r1)
@@ -538,18 +539,23 @@
 	lwz	r8,TI_PREEMPT(r9)
 	cmpwi	cr1,r8,0
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
 	ld	r0,SOFTE(r1)
 	cmpdi	r0,0
-#else
-	andi.	r0,r3,MSR_EE
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
+BEGIN_FW_FTR_SECTION
+	andi.	r0,r3,MSR_EE
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
 	crandc	eq,cr1*4+eq,eq
 	bne	restore
 	/* here we are preempting the current task */
 1:
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
 	li	r0,1
 	stb	r0,PACAPROCENABLED(r13)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
 	ori	r10,r10,MSR_EE
 	mtmsrd	r10,1		/* reenable interrupts */
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 3065b47..645c7f1 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -33,6 +33,7 @@
 #include <asm/hvcall.h>
 #include <asm/iseries/lpar_map.h>
 #include <asm/thread_info.h>
+#include <asm/firmware.h>
 
 #ifdef CONFIG_PPC_ISERIES
 #define DO_SOFT_DISABLE
@@ -365,19 +366,28 @@
 
 #ifdef DO_SOFT_DISABLE
 #define DISABLE_INTS				\
+BEGIN_FW_FTR_SECTION;				\
 	lbz	r10,PACAPROCENABLED(r13);	\
 	li	r11,0;				\
 	std	r10,SOFTE(r1);			\
 	mfmsr	r10;				\
 	stb	r11,PACAPROCENABLED(r13);	\
 	ori	r10,r10,MSR_EE;			\
-	mtmsrd	r10,1
+	mtmsrd	r10,1;				\
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 
 #define ENABLE_INTS				\
+BEGIN_FW_FTR_SECTION;				\
 	lbz	r10,PACAPROCENABLED(r13);	\
 	mfmsr	r11;				\
 	std	r10,SOFTE(r1);			\
 	ori	r11,r11,MSR_EE;			\
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES);	\
+BEGIN_FW_FTR_SECTION;				\
+	ld	r12,_MSR(r1);			\
+	mfmsr	r11;				\
+	rlwimi	r11,r12,0,MSR_EE;		\
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES);	\
 	mtmsrd	r11,1
 
 #else	/* hard enable/disable interrupts */
@@ -1071,8 +1081,10 @@
 	ld	r3,PACA_EXSLB+EX_R3(r13)
 	lwz	r9,PACA_EXSLB+EX_CCR(r13)	/* get saved CR */
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
 	ld	r11,PACALPPACAPTR(r13)
 	ld	r11,LPPACASRR0(r11)		/* get SRR0 value */
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif /* CONFIG_PPC_ISERIES */
 
 	mtlr	r10
@@ -1087,8 +1099,10 @@
 .machine	pop
 
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
 	mtspr	SPRN_SRR0,r11
 	mtspr	SPRN_SRR1,r12
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif /* CONFIG_PPC_ISERIES */
 	ld	r9,PACA_EXSLB+EX_R9(r13)
 	ld	r10,PACA_EXSLB+EX_R10(r13)
@@ -1301,6 +1315,7 @@
 	cmpdi	r3,0			/* see if hash_page succeeded */
 
 #ifdef DO_SOFT_DISABLE
+BEGIN_FW_FTR_SECTION
 	/*
 	 * If we had interrupts soft-enabled at the point where the
 	 * DSI/ISI occurred, and an interrupt came in during hash_page,
@@ -1321,12 +1336,14 @@
 	ld	r3,SOFTE(r1)
 	bl	.local_irq_restore
 	b	11f
-#else
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+#endif
+BEGIN_FW_FTR_SECTION
 	beq	fast_exception_return   /* Return from exception on success */
 	ble-	12f			/* Failure return from hash_page */
 
 	/* fall through */
-#endif
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
 
 /* Here we have a page fault that hash_page can't handle. */
 _GLOBAL(handle_page_fault)
@@ -1861,7 +1878,9 @@
 	LOAD_REG_ADDR(r3, .start_secondary_prolog)
 	LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
 #ifdef DO_SOFT_DISABLE
+BEGIN_FW_FTR_SECTION
 	ori	r4,r4,MSR_EE
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
 	mtspr	SPRN_SRR0,r3
 	mtspr	SPRN_SRR1,r4
@@ -1986,6 +2005,7 @@
 	 */
 	li	r3,0
 	bl	.do_cpu_ftr_fixups
+	bl	.do_fw_ftr_fixups
 
 	/* ptr to current */
 	LOAD_REG_IMMEDIATE(r4, init_task)
@@ -2000,11 +2020,13 @@
 	/* Load up the kernel context */
 5:
 #ifdef DO_SOFT_DISABLE
+BEGIN_FW_FTR_SECTION
 	li	r5,0
 	stb	r5,PACAPROCENABLED(r13)	/* Soft Disabled */
 	mfmsr	r5
 	ori	r5,r5,MSR_EE		/* Hard Enabled */
 	mtmsrd	r5
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif
 
 	bl .start_kernel
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 9c54ecc..41521b3 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -325,6 +325,52 @@
 	isync
 	b	1b
 
+/*
+ * do_fw_ftr_fixups - goes through the list of firmware feature fixups
+ * and writes nop's over sections of code that don't apply for this firmware.
+ * r3 = data offset (not changed)
+ */
+_GLOBAL(do_fw_ftr_fixups)
+	/* Get firmware features */
+	LOAD_REG_IMMEDIATE(r6,powerpc_firmware_features)
+	sub	r6,r6,r3
+	ld	r4,0(r6)
+	/* Get the fixup table */
+	LOAD_REG_IMMEDIATE(r6,__start___fw_ftr_fixup)
+	sub	r6,r6,r3
+	LOAD_REG_IMMEDIATE(r7,__stop___fw_ftr_fixup)
+	sub	r7,r7,r3
+	/* Do the fixup */
+1:	cmpld	r6,r7
+	bgelr
+	addi	r6,r6,32
+	ld	r8,-32(r6)	/* mask */
+	and	r8,r8,r4
+	ld	r9,-24(r6)	/* value */
+	cmpld	r8,r9
+	beq	1b
+	ld	r8,-16(r6)	/* section begin */
+	ld	r9,-8(r6)	/* section end */
+	subf.	r9,r8,r9
+	beq	1b
+	/* write nops over the section of code */
+	/* todo: if large section, add a branch at the start of it */
+	srwi	r9,r9,2
+	mtctr	r9
+	sub	r8,r8,r3
+	lis	r0,0x60000000@h	/* nop */
+3:	stw	r0,0(r8)
+BEGIN_FTR_SECTION
+	dcbst	0,r8		/* suboptimal, but simpler */
+	sync
+	icbi	0,r8
+END_FTR_SECTION_IFSET(CPU_FTR_SPLIT_ID_CACHE)
+	addi	r8,r8,4
+	bdnz	3b
+	sync			/* additional sync needed on g4 */
+	isync
+	b	1b
+
 #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
 /*
  * Do an IO access in real mode
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index c1b1e14..78d3c0f 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -30,6 +30,7 @@
 #include <asm/byteorder.h>
 #include <asm/machdep.h>
 #include <asm/ppc-pci.h>
+#include <asm/firmware.h>
 
 #ifdef DEBUG
 #include <asm/udbg.h>
@@ -209,7 +210,6 @@
 		kfree(phb);
 }
 
-#ifndef CONFIG_PPC_ISERIES
 void __devinit pcibios_claim_one_bus(struct pci_bus *b)
 {
 	struct pci_dev *dev;
@@ -238,10 +238,12 @@
 {
 	struct pci_bus *b;
 
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		return;
+
 	list_for_each_entry(b, &pci_root_buses, node)
 		pcibios_claim_one_bus(b);
 }
-#endif
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
 static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
@@ -554,9 +556,8 @@
 	 */
 	ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
 
-#ifdef CONFIG_PPC_ISERIES
-	iSeries_pcibios_init(); 
-#endif
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		iSeries_pcibios_init();
 
 	printk(KERN_DEBUG "PCI: Probing PCI hardware\n");
 
@@ -566,15 +567,15 @@
 		pci_bus_add_devices(hose->bus);
 	}
 
-#ifndef CONFIG_PPC_ISERIES
-	if (pci_probe_only)
-		pcibios_claim_of_setup();
-	else
-		/* FIXME: `else' will be removed when
-		   pci_assign_unassigned_resources() is able to work
-		   correctly with [partially] allocated PCI tree. */
-		pci_assign_unassigned_resources();
-#endif /* !CONFIG_PPC_ISERIES */
+	if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
+		if (pci_probe_only)
+			pcibios_claim_of_setup();
+		else
+			/* FIXME: `else' will be removed when
+			   pci_assign_unassigned_resources() is able to work
+			   correctly with [partially] allocated PCI tree. */
+			pci_assign_unassigned_resources();
+	}
 
 	/* Call machine dependent final fixup */
 	if (ppc_md.pcibios_fixup)
@@ -586,8 +587,9 @@
 		printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
 
 #ifdef CONFIG_PPC_MULTIPLATFORM
-	/* map in PCI I/O space */
-	phbs_remap_io();
+	if (!firmware_has_feature(FW_FEATURE_ISERIES))
+		/* map in PCI I/O space */
+		phbs_remap_io();
 #endif
 
 	printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");
@@ -637,13 +639,13 @@
  */
 int pci_domain_nr(struct pci_bus *bus)
 {
-#ifdef CONFIG_PPC_ISERIES
-	return 0;
-#else
-	struct pci_controller *hose = pci_bus_to_host(bus);
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		return 0;
+	else {
+		struct pci_controller *hose = pci_bus_to_host(bus);
 
-	return hose->global_number;
-#endif
+		return hose->global_number;
+	}
 }
 
 EXPORT_SYMBOL(pci_domain_nr);
@@ -651,12 +653,12 @@
 /* Decide whether to display the domain number in /proc */
 int pci_proc_domain(struct pci_bus *bus)
 {
-#ifdef CONFIG_PPC_ISERIES
-	return 0;
-#else
-	struct pci_controller *hose = pci_bus_to_host(bus);
-	return hose->buid;
-#endif
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		return 0;
+	else {
+		struct pci_controller *hose = pci_bus_to_host(bus);
+		return hose->buid;
+	}
 }
 
 /*
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 0af3fc1..89cfaf4 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -442,31 +442,6 @@
 }
 #endif /* CONFIG_SMP */
 
-int __initdata do_early_xmon;
-#ifdef CONFIG_XMON
-extern int xmon_no_auto_backtrace;
-
-static int __init early_xmon(char *p)
-{
-	/* ensure xmon is enabled */
-	if (p) {
-		if (strncmp(p, "on", 2) == 0)
-			xmon_init(1);
-		if (strncmp(p, "off", 3) == 0)
-			xmon_init(0);
-		if (strncmp(p, "nobt", 4) == 0)
-			xmon_no_auto_backtrace = 1;
-		if (strncmp(p, "early", 5) != 0)
-			return 0;
-	}
-	xmon_init(1);
-	do_early_xmon = 1;
-
-	return 0;
-}
-early_param("xmon", early_xmon);
-#endif
-
 static __init int add_pcspkr(void)
 {
 	struct device_node *np;
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 79a1779..191d0ab 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -238,12 +238,11 @@
 
 	smp_setup_cpu_maps();
 
-#ifdef CONFIG_XMON_DEFAULT
-	xmon_init(1);
-#endif
 	/* Register early console */
 	register_early_udbg_console();
 
+	xmon_setup();
+
 #if defined(CONFIG_KGDB)
 	if (ppc_md.kgdb_map_scc)
 		ppc_md.kgdb_map_scc();
@@ -280,9 +279,6 @@
 	init_mm.end_data = (unsigned long) _edata;
 	init_mm.brk = klimit;
 
-	if (do_early_xmon)
-		debugger(NULL);
-
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
 	if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index cda2dbe..4b2e32e 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -391,18 +391,14 @@
 	find_legacy_serial_ports();
 
 	/*
-	 * Initialize xmon
-	 */
-#ifdef CONFIG_XMON_DEFAULT
-	xmon_init(1);
-#endif
-	/*
 	 * Register early console
 	 */
 	register_early_udbg_console();
 
-	if (do_early_xmon)
-		debugger(NULL);
+	/*
+	 * Initialize xmon
+	 */
+	xmon_setup();
 
 	check_smt_enabled();
 	smp_setup_cpu_maps();
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 02665a0..cb0e8d4 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -132,6 +132,14 @@
 		*(__ftr_fixup)
 		__stop___ftr_fixup = .;
 	}
+#ifdef CONFIG_PPC64
+	. = ALIGN(8);
+	__fw_ftr_fixup : {
+		__start___fw_ftr_fixup = .;
+		*(__fw_ftr_fixup)
+		__stop___fw_ftr_fixup = .;
+	}
+#endif
 
 	. = ALIGN(PAGE_SIZE);
 	.init.ramfs : {
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index b1da031..ac64f4a 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -63,32 +63,13 @@
 #include <asm/iommu.h>
 #include <asm/abs_addr.h>
 #include <asm/vdso.h>
+#include <asm/firmware.h>
 
 #include "mmu_decl.h"
 
 unsigned long ioremap_bot = IMALLOC_BASE;
 static unsigned long phbs_io_bot = PHBS_IO_BASE;
 
-#ifdef CONFIG_PPC_ISERIES
-
-void __iomem *ioremap(unsigned long addr, unsigned long size)
-{
-	return (void __iomem *)addr;
-}
-
-extern void __iomem *__ioremap(unsigned long addr, unsigned long size,
-		       unsigned long flags)
-{
-	return (void __iomem *)addr;
-}
-
-void iounmap(volatile void __iomem *addr)
-{
-	return;
-}
-
-#else
-
 /*
  * map_io_page currently only called by __ioremap
  * map_io_page adds an entry to the ioremap page table
@@ -161,6 +142,9 @@
 	unsigned long pa, ea;
 	void __iomem *ret;
 
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		return (void __iomem *)addr;
+
 	/*
 	 * Choose an address to map it to.
 	 * Once the imalloc system is running, we use it.
@@ -255,6 +239,9 @@
 {
 	void *addr;
 
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		return;
+
 	if (!mem_init_done)
 		return;
 	
@@ -315,8 +302,6 @@
 	return 0;
 }
 
-#endif
-
 EXPORT_SYMBOL(ioremap);
 EXPORT_SYMBOL(__ioremap);
 EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index dbc1abbd..b10e470 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -21,6 +21,7 @@
 #include <asm/page.h>
 #include <asm/mmu.h>
 #include <asm/pgtable.h>
+#include <asm/firmware.h>
 
 /* void slb_allocate_realmode(unsigned long ea);
  *
@@ -183,6 +184,7 @@
  	 * dont have any LRU information to help us choose a slot.
  	 */
 #ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
 	/*
 	 * On iSeries, the "bolted" stack segment can be cast out on
 	 * shared processor switch so we need to check for a miss on
@@ -194,6 +196,7 @@
 	li	r10,SLB_NUM_BOLTED-1	/* Stack goes in last bolted slot */
 	cmpld	r9,r3
 	beq	3f
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
 #endif /* CONFIG_PPC_ISERIES */
 
 	ld	r10,PACASTABRR(r13)
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
new file mode 100644
index 0000000..47d841e
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/Kconfig
@@ -0,0 +1,21 @@
+menu "Platform support"
+       depends on PPC_82xx
+
+choice
+       prompt "Machine Type"
+       default MPC82xx_ADS
+
+config MPC82xx_ADS
+       bool "Freescale MPC82xx ADS"
+       select DEFAULT_UIMAGE
+       select PQ2ADS
+       select 8272
+       select 8260
+       select CPM2
+       select FSL_SOC
+       help
+         This option enables support for the MPC8272 ADS board
+
+endchoice
+
+endmenu
diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile
new file mode 100644
index 0000000..d9fd4c8
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the PowerPC 82xx linux kernel.
+#
+obj-$(CONFIG_PPC_82xx) += mpc82xx.o
+obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o
diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h
new file mode 100644
index 0000000..9cd8893
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/m82xx_pci.h
@@ -0,0 +1,19 @@
+#ifndef _PPC_KERNEL_M82XX_PCI_H
+#define _PPC_KERNEL_M82XX_PCI_H
+
+/*
+ * 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 <asm/m8260_pci.h>
+
+#define SIU_INT_IRQ1   ((uint)0x13 + CPM_IRQ_OFFSET)
+
+#ifndef _IO_BASE
+#define _IO_BASE isa_io_base
+#endif
+
+#endif				/* _PPC_KERNEL_M8260_PCI_H */
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
new file mode 100644
index 0000000..89d702d
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -0,0 +1,111 @@
+/*
+ * MPC82xx setup and early boot code plus other random bits.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright (c) 2006 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#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/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+#include <linux/fs_uart_pd.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc8260.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/cpm2.h>
+#include <asm/udbg.h>
+#include <asm/i8259.h>
+#include <linux/fs_enet_pd.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/cpm2_pic.h>
+
+#include "pq2ads_pd.h"
+
+static int __init get_freq(char *name, unsigned long *val)
+{
+	struct device_node *cpu;
+	unsigned int *fp;
+	int found = 0;
+
+	/* The cpu node should have timebase and clock frequency properties */
+	cpu = of_find_node_by_type(NULL, "cpu");
+
+	if (cpu) {
+		fp = (unsigned int *)get_property(cpu, name, NULL);
+		if (fp) {
+			found = 1;
+			*val = *fp++;
+		}
+
+		of_node_put(cpu);
+	}
+
+	return found;
+}
+
+void __init m82xx_calibrate_decr(void)
+{
+	ppc_tb_freq = 125000000;
+	if (!get_freq("bus-frequency", &ppc_tb_freq)) {
+		printk(KERN_ERR "WARNING: Estimating decrementer frequency "
+				"(not found)\n");
+	}
+	ppc_tb_freq /= 4;
+	ppc_proc_freq = 1000000000;
+	if (!get_freq("clock-frequency", &ppc_proc_freq))
+		printk(KERN_ERR "WARNING: Estimating processor frequency"
+				"(not found)\n");
+}
+
+void mpc82xx_ads_show_cpuinfo(struct seq_file *m)
+{
+	uint pvid, svid, phid1;
+	uint memsize = total_memory;
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+
+	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+	seq_printf(m, "Machine\t\t: %s\n", CPUINFO_MACHINE);
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
new file mode 100644
index 0000000..4276f08
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -0,0 +1,661 @@
+/*
+ * MPC82xx_ads setup and early boot code plus other random bits.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ * m82xx_restart fix by Wade Farnsworth <wfarnsworth@mvista.com>
+ *
+ * Copyright (c) 2006 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+
+#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/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+#include <linux/fs_uart_pd.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc8260.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/cpm2.h>
+#include <asm/udbg.h>
+#include <asm/i8259.h>
+#include <linux/fs_enet_pd.h>
+
+#include <sysdev/fsl_soc.h>
+#include <../sysdev/cpm2_pic.h>
+
+#include "pq2ads_pd.h"
+
+#ifdef CONFIG_PCI
+static uint pci_clk_frq;
+static struct {
+	unsigned long *pci_int_stat_reg;
+	unsigned long *pci_int_mask_reg;
+} pci_regs;
+
+static unsigned long pci_int_base;
+static struct irq_host *pci_pic_host;
+static struct device_node *pci_pic_node;
+#endif
+
+static void __init mpc82xx_ads_pic_init(void)
+{
+	struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2");
+	struct resource r;
+	cpm2_map_t *cpm_reg;
+
+	if (np == NULL) {
+		printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
+		return;
+	}
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_ERR "PIC init: invalid resource\n");
+		of_node_put(np);
+		return;
+	}
+	cpm2_pic_init(np);
+	of_node_put(np);
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	cpm_reg = (cpm2_map_t *) ioremap(get_immrbase(), sizeof(cpm2_map_t));
+	cpm_reg->im_intctl.ic_siprr = 0x05309770;
+	iounmap(cpm_reg);
+#ifdef CONFIG_PCI
+	/* Initialize stuff for the 82xx CPLD IC and install demux  */
+	m82xx_pci_init_irq();
+#endif
+}
+
+static void init_fcc1_ioports(struct fs_platform_info *fpi)
+{
+	struct io_port *io;
+	u32 tempval;
+	cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+	struct device_node *np;
+	struct resource r;
+	u32 *bcsr;
+
+	np = of_find_node_by_type(NULL, "memory");
+	if (!np) {
+		printk(KERN_INFO "No memory node in device tree\n");
+		return;
+	}
+	if (of_address_to_resource(np, 1, &r)) {
+		printk(KERN_INFO "No memory reg property [1] in devicetree\n");
+		return;
+	}
+	of_node_put(np);
+	bcsr = ioremap(r.start + 4, sizeof(u32));
+	io = &immap->im_ioport;
+
+	/* Enable the PHY */
+	clrbits32(bcsr, BCSR1_FETHIEN);
+	setbits32(bcsr, BCSR1_FETH_RST);
+
+	/* FCC1 pins are on port A/C. */
+	/* Configure port A and C pins for FCC1 Ethernet. */
+
+	tempval = in_be32(&io->iop_pdira);
+	tempval &= ~PA1_DIRA0;
+	tempval |= PA1_DIRA1;
+	out_be32(&io->iop_pdira, tempval);
+
+	tempval = in_be32(&io->iop_psora);
+	tempval &= ~PA1_PSORA0;
+	tempval |= PA1_PSORA1;
+	out_be32(&io->iop_psora, tempval);
+
+	setbits32(&io->iop_ppara, PA1_DIRA0 | PA1_DIRA1);
+
+	/* Alter clocks */
+	tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8);
+
+	clrbits32(&io->iop_psorc, tempval);
+	clrbits32(&io->iop_pdirc, tempval);
+	setbits32(&io->iop_pparc, tempval);
+
+	cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_rx, CPM_CLK_RX);
+	cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_tx, CPM_CLK_TX);
+
+	iounmap(bcsr);
+	iounmap(immap);
+}
+
+static void init_fcc2_ioports(struct fs_platform_info *fpi)
+{
+	cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+	struct device_node *np;
+	struct resource r;
+	u32 *bcsr;
+
+	struct io_port *io;
+	u32 tempval;
+
+	np = of_find_node_by_type(NULL, "memory");
+	if (!np) {
+		printk(KERN_INFO "No memory node in device tree\n");
+		return;
+	}
+	if (of_address_to_resource(np, 1, &r)) {
+		printk(KERN_INFO "No memory reg property [1] in devicetree\n");
+		return;
+	}
+	of_node_put(np);
+	io = &immap->im_ioport;
+	bcsr = ioremap(r.start + 12, sizeof(u32));
+
+	/* Enable the PHY */
+	clrbits32(bcsr, BCSR3_FETHIEN2);
+	setbits32(bcsr, BCSR3_FETH2_RST);
+
+	/* FCC2 are port B/C. */
+	/* Configure port A and C pins for FCC2 Ethernet. */
+
+	tempval = in_be32(&io->iop_pdirb);
+	tempval &= ~PB2_DIRB0;
+	tempval |= PB2_DIRB1;
+	out_be32(&io->iop_pdirb, tempval);
+
+	tempval = in_be32(&io->iop_psorb);
+	tempval &= ~PB2_PSORB0;
+	tempval |= PB2_PSORB1;
+	out_be32(&io->iop_psorb, tempval);
+
+	setbits32(&io->iop_pparb, PB2_DIRB0 | PB2_DIRB1);
+
+	tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8);
+
+	/* Alter clocks */
+	clrbits32(&io->iop_psorc, tempval);
+	clrbits32(&io->iop_pdirc, tempval);
+	setbits32(&io->iop_pparc, tempval);
+
+	cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_rx, CPM_CLK_RX);
+	cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_tx, CPM_CLK_TX);
+
+	iounmap(bcsr);
+	iounmap(immap);
+}
+
+void init_fcc_ioports(struct fs_platform_info *fpi)
+{
+	int fcc_no = fs_get_fcc_index(fpi->fs_no);
+
+	switch (fcc_no) {
+	case 0:
+		init_fcc1_ioports(fpi);
+		break;
+	case 1:
+		init_fcc2_ioports(fpi);
+		break;
+	default:
+		printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n");
+		return;
+	}
+}
+
+static void init_scc1_uart_ioports(struct fs_uart_platform_info *data)
+{
+	cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+
+	/* SCC1 is only on port D */
+	setbits32(&immap->im_ioport.iop_ppard, 0x00000003);
+	clrbits32(&immap->im_ioport.iop_psord, 0x00000001);
+	setbits32(&immap->im_ioport.iop_psord, 0x00000002);
+	clrbits32(&immap->im_ioport.iop_pdird, 0x00000001);
+	setbits32(&immap->im_ioport.iop_pdird, 0x00000002);
+
+	clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx)));
+	clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx)));
+	setbits32(&immap->im_cpmux.cmx_scr,
+		  ((data->clk_tx - 1) << (4 - data->clk_tx)));
+	setbits32(&immap->im_cpmux.cmx_scr,
+		  ((data->clk_rx - 1) << (4 - data->clk_rx)));
+
+	iounmap(immap);
+}
+
+static void init_scc4_uart_ioports(struct fs_uart_platform_info *data)
+{
+	cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+
+	setbits32(&immap->im_ioport.iop_ppard, 0x00000600);
+	clrbits32(&immap->im_ioport.iop_psord, 0x00000600);
+	clrbits32(&immap->im_ioport.iop_pdird, 0x00000200);
+	setbits32(&immap->im_ioport.iop_pdird, 0x00000400);
+
+	clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx)));
+	clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx)));
+	setbits32(&immap->im_cpmux.cmx_scr,
+		  ((data->clk_tx - 1) << (4 - data->clk_tx)));
+	setbits32(&immap->im_cpmux.cmx_scr,
+		  ((data->clk_rx - 1) << (4 - data->clk_rx)));
+
+	iounmap(immap);
+}
+
+void init_scc_ioports(struct fs_uart_platform_info *data)
+{
+	int scc_no = fs_get_scc_index(data->fs_no);
+
+	switch (scc_no) {
+	case 0:
+		init_scc1_uart_ioports(data);
+		data->brg = data->clk_rx;
+		break;
+	case 3:
+		init_scc4_uart_ioports(data);
+		data->brg = data->clk_rx;
+		break;
+	default:
+		printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+		return;
+	}
+}
+
+void __init m82xx_board_setup(void)
+{
+	cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+	struct device_node *np;
+	struct resource r;
+	u32 *bcsr;
+
+	np = of_find_node_by_type(NULL, "memory");
+	if (!np) {
+		printk(KERN_INFO "No memory node in device tree\n");
+		return;
+	}
+	if (of_address_to_resource(np, 1, &r)) {
+		printk(KERN_INFO "No memory reg property [1] in devicetree\n");
+		return;
+	}
+	of_node_put(np);
+	bcsr = ioremap(r.start + 4, sizeof(u32));
+	/* Enable the 2nd UART port */
+	clrbits32(bcsr, BCSR1_RS232_EN2);
+
+#ifdef CONFIG_SERIAL_CPM_SCC1
+	clrbits32((u32 *) & immap->im_scc[0].scc_sccm,
+		  UART_SCCM_TX | UART_SCCM_RX);
+	clrbits32((u32 *) & immap->im_scc[0].scc_gsmrl,
+		  SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC2
+	clrbits32((u32 *) & immap->im_scc[1].scc_sccm,
+		  UART_SCCM_TX | UART_SCCM_RX);
+	clrbits32((u32 *) & immap->im_scc[1].scc_gsmrl,
+		  SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC3
+	clrbits32((u32 *) & immap->im_scc[2].scc_sccm,
+		  UART_SCCM_TX | UART_SCCM_RX);
+	clrbits32((u32 *) & immap->im_scc[2].scc_gsmrl,
+		  SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC4
+	clrbits32((u32 *) & immap->im_scc[3].scc_sccm,
+		  UART_SCCM_TX | UART_SCCM_RX);
+	clrbits32((u32 *) & immap->im_scc[3].scc_gsmrl,
+		  SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+	iounmap(bcsr);
+	iounmap(immap);
+}
+
+#ifdef CONFIG_PCI
+static void m82xx_pci_mask_irq(unsigned int irq)
+{
+	int bit = irq - pci_int_base;
+
+	*pci_regs.pci_int_mask_reg |= (1 << (31 - bit));
+	return;
+}
+
+static void m82xx_pci_unmask_irq(unsigned int irq)
+{
+	int bit = irq - pci_int_base;
+
+	*pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit));
+	return;
+}
+
+static void m82xx_pci_mask_and_ack(unsigned int irq)
+{
+	int bit = irq - pci_int_base;
+
+	*pci_regs.pci_int_mask_reg |= (1 << (31 - bit));
+	return;
+}
+
+static void m82xx_pci_end_irq(unsigned int irq)
+{
+	int bit = irq - pci_int_base;
+
+	*pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit));
+	return;
+}
+
+struct hw_interrupt_type m82xx_pci_ic = {
+	.typename = "MPC82xx ADS PCI",
+	.name = "MPC82xx ADS PCI",
+	.enable = m82xx_pci_unmask_irq,
+	.disable = m82xx_pci_mask_irq,
+	.ack = m82xx_pci_mask_and_ack,
+	.end = m82xx_pci_end_irq,
+	.mask = m82xx_pci_mask_irq,
+	.mask_ack = m82xx_pci_mask_and_ack,
+	.unmask = m82xx_pci_unmask_irq,
+	.eoi = m82xx_pci_end_irq,
+};
+
+static void
+m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc,
+		    struct pt_regs *regs)
+{
+	unsigned long stat, mask, pend;
+	int bit;
+
+	for (;;) {
+		stat = *pci_regs.pci_int_stat_reg;
+		mask = *pci_regs.pci_int_mask_reg;
+		pend = stat & ~mask & 0xf0000000;
+		if (!pend)
+			break;
+		for (bit = 0; pend != 0; ++bit, pend <<= 1) {
+			if (pend & 0x80000000)
+				__do_IRQ(pci_int_base + bit, regs);
+		}
+	}
+}
+
+static int pci_pic_host_match(struct irq_host *h, struct device_node *node)
+{
+	return node == pci_pic_node;
+}
+
+static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
+			    irq_hw_number_t hw)
+{
+	get_irq_desc(virq)->status |= IRQ_LEVEL;
+	set_irq_chip(virq, &m82xx_pci_ic);
+	return 0;
+}
+
+static void pci_host_unmap(struct irq_host *h, unsigned int virq)
+{
+	/* remove chip and handler */
+	set_irq_chip(virq, NULL);
+}
+
+static struct irq_host_ops pci_pic_host_ops = {
+	.match = pci_pic_host_match,
+	.map = pci_pic_host_map,
+	.unmap = pci_host_unmap,
+};
+
+void m82xx_pci_init_irq(void)
+{
+	int irq;
+	cpm2_map_t *immap;
+	struct device_node *np;
+	struct resource r;
+	const u32 *regs;
+	unsigned int size;
+	const u32 *irq_map;
+	int i;
+	unsigned int irq_max, irq_min;
+
+	if ((np = of_find_node_by_type(NULL, "soc")) == NULL) {
+		printk(KERN_INFO "No SOC node in device tree\n");
+		return;
+	}
+	memset(&r, 0, sizeof(r));
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_INFO "No SOC reg property in device tree\n");
+		return;
+	}
+	immap = ioremap(r.start, sizeof(*immap));
+	of_node_put(np);
+
+	/* install the demultiplexer for the PCI cascade interrupt */
+	np = of_find_node_by_type(NULL, "pci");
+	if (!np) {
+		printk(KERN_INFO "No pci node on device tree\n");
+		iounmap(immap);
+		return;
+	}
+	irq_map = get_property(np, "interrupt-map", &size);
+	if ((!irq_map) || (size <= 7)) {
+		printk(KERN_INFO "No interrupt-map property of pci node\n");
+		iounmap(immap);
+		return;
+	}
+	size /= sizeof(irq_map[0]);
+	for (i = 0, irq_max = 0, irq_min = 512; i < size; i += 7, irq_map += 7) {
+		if (irq_map[5] < irq_min)
+			irq_min = irq_map[5];
+		if (irq_map[5] > irq_max)
+			irq_max = irq_map[5];
+	}
+	pci_int_base = irq_min;
+	irq = irq_of_parse_and_map(np, 0);
+	set_irq_chained_handler(irq, m82xx_pci_irq_demux);
+	of_node_put(np);
+	np = of_find_node_by_type(NULL, "pci-pic");
+	if (!np) {
+		printk(KERN_INFO "No pci pic node on device tree\n");
+		iounmap(immap);
+		return;
+	}
+	pci_pic_node = of_node_get(np);
+	/* PCI interrupt controller registers: status and mask */
+	regs = get_property(np, "reg", &size);
+	if ((!regs) || (size <= 2)) {
+		printk(KERN_INFO "No reg property in pci pic node\n");
+		iounmap(immap);
+		return;
+	}
+	pci_regs.pci_int_stat_reg =
+	    ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg));
+	pci_regs.pci_int_mask_reg =
+	    ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg));
+	of_node_put(np);
+	/* configure chip select for PCI interrupt controller */
+	immap->im_memctl.memc_br3 = regs[0] | 0x00001801;
+	immap->im_memctl.memc_or3 = 0xffff8010;
+	/* make PCI IRQ level sensitive */
+	immap->im_intctl.ic_siexr &= ~(1 << (14 - (irq - SIU_INT_IRQ1)));
+
+	/* mask all PCI interrupts */
+	*pci_regs.pci_int_mask_reg |= 0xfff00000;
+	iounmap(immap);
+	pci_pic_host =
+	    irq_alloc_host(IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1,
+			   &pci_pic_host_ops, irq_max + 1);
+	return;
+}
+
+static int m82xx_pci_exclude_device(u_char bus, u_char devfn)
+{
+	if (bus == 0 && PCI_SLOT(devfn) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	else
+		return PCIBIOS_SUCCESSFUL;
+}
+
+static void
+__init mpc82xx_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+
+	for_each_pci_dev(dev) {
+		pci_read_irq_line(dev);
+	}
+}
+
+void __init add_bridge(struct device_node *np)
+{
+	int len;
+	struct pci_controller *hose;
+	struct resource r;
+	const int *bus_range;
+	const void *ptr;
+
+	memset(&r, 0, sizeof(r));
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_INFO "No PCI reg property in device tree\n");
+		return;
+	}
+	if (!(ptr = get_property(np, "clock-frequency", NULL))) {
+		printk(KERN_INFO "No clock-frequency property in PCI node");
+		return;
+	}
+	pci_clk_frq = *(uint *) ptr;
+	of_node_put(np);
+	bus_range = get_property(np, "bus-range", &len);
+	if (bus_range == NULL || len < 2 * sizeof(int)) {
+		printk(KERN_WARNING "Can't get bus-range for %s, assume"
+		       " bus 0\n", np->full_name);
+	}
+
+	pci_assign_all_buses = 1;
+
+	hose = pcibios_alloc_controller();
+
+	if (!hose)
+		return;
+
+	hose->arch_data = np;
+	hose->set_cfg_type = 1;
+
+	hose->first_busno = bus_range ? bus_range[0] : 0;
+	hose->last_busno = bus_range ? bus_range[1] : 0xff;
+	hose->bus_offset = 0;
+
+	hose->set_cfg_type = 1;
+
+	setup_indirect_pci(hose,
+			   r.start + offsetof(pci_cpm2_t, pci_cfg_addr),
+			   r.start + offsetof(pci_cpm2_t, pci_cfg_data));
+
+	pci_process_bridge_OF_ranges(hose, np, 1);
+}
+#endif
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc82xx_ads_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+	struct device_node *np;
+#endif
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc82xx_ads_setup_arch()", 0);
+	cpm2_reset();
+
+	/* Map I/O region to a 256MB BAT */
+
+	m82xx_board_setup();
+
+#ifdef CONFIG_PCI
+	ppc_md.pci_exclude_device = m82xx_pci_exclude_device;
+	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+		add_bridge(np);
+
+	of_node_put(np);
+	ppc_md.pci_map_irq = NULL;
+	ppc_md.pcibios_fixup = mpc82xx_pcibios_fixup;
+	ppc_md.pcibios_fixup_bus = NULL;
+#endif
+
+#ifdef  CONFIG_ROOT_NFS
+	ROOT_DEV = Root_NFS;
+#else
+	ROOT_DEV = Root_HDA1;
+#endif
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc82xx_ads_setup_arch(), finish", 0);
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc82xx_ads_probe(void)
+{
+	/* We always match for now, eventually we should look at
+	 * the flat dev tree to ensure this is the board we are
+	 * supposed to run on
+	 */
+	return 1;
+}
+
+#define RMR_CSRE 0x00000001
+static void m82xx_restart(char *cmd)
+{
+	__volatile__ unsigned char dummy;
+
+	local_irq_disable();
+	((cpm2_map_t *) cpm2_immr)->im_clkrst.car_rmr |= RMR_CSRE;
+
+	/* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */
+	mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR));
+	dummy = ((cpm2_map_t *) cpm2_immr)->im_clkrst.res[0];
+	printk("Restart failed\n");
+	while (1) ;
+}
+
+static void m82xx_halt(void)
+{
+	local_irq_disable();
+	while (1) ;
+}
+
+define_machine(mpc82xx_ads)
+{
+	.name = "MPC82xx ADS",
+	.probe = mpc82xx_ads_probe,
+	.setup_arch =    mpc82xx_ads_setup_arch,
+	.init_IRQ =    mpc82xx_ads_pic_init,
+	.show_cpuinfo =    mpc82xx_ads_show_cpuinfo,
+	.get_irq =    cpm2_get_irq,
+	.calibrate_decr =    m82xx_calibrate_decr,
+	.restart = m82xx_restart,.halt = m82xx_halt,
+};
diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h
new file mode 100644
index 0000000..a734821
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/pq2ads.h
@@ -0,0 +1,67 @@
+/*
+ * PQ2/mpc8260 board-specific stuff
+ *
+ * A collection of structures, addresses, and values associated with
+ * the Freescale MPC8260ADS/MPC8266ADS-PCI boards.
+ * Copied from the RPX-Classic and SBS8260 stuff.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Originally written by Dan Malek for Motorola MPC8260 family
+ *
+ * Copyright (c) 2001 Dan Malek <dan@embeddedalley.com>
+ * Copyright (c) 2006 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifdef __KERNEL__
+#ifndef __MACH_ADS8260_DEFS
+#define __MACH_ADS8260_DEFS
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR		"Freescale Semiconductor"
+#define CPUINFO_MACHINE		"PQ2 ADS PowerPC"
+
+/* Backword-compatibility stuff for the drivers */
+#define CPM_MAP_ADDR		((uint)0xf0000000)
+#define CPM_IRQ_OFFSET 0
+
+/* The ADS8260 has 16, 32-bit wide control/status registers, accessed
+ * only on word boundaries.
+ * Not all are used (yet), or are interesting to us (yet).
+ */
+
+/* Things of interest in the CSR.
+ */
+#define BCSR0_LED0		((uint)0x02000000)      /* 0 == on */
+#define BCSR0_LED1		((uint)0x01000000)      /* 0 == on */
+#define BCSR1_FETHIEN		((uint)0x08000000)      /* 0 == enable*/
+#define BCSR1_FETH_RST		((uint)0x04000000)      /* 0 == reset */
+#define BCSR1_RS232_EN1		((uint)0x02000000)      /* 0 ==enable */
+#define BCSR1_RS232_EN2		((uint)0x01000000)      /* 0 ==enable */
+#define BCSR3_FETHIEN2		((uint)0x10000000)      /* 0 == enable*/
+#define BCSR3_FETH2_RS		((uint)0x80000000)      /* 0 == reset */
+
+/* cpm serial driver works with constants below */
+
+#define SIU_INT_SMC1		((uint)0x04+CPM_IRQ_OFFSET)
+#define SIU_INT_SMC2i		((uint)0x05+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC1		((uint)0x28+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC2		((uint)0x29+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC3		((uint)0x2a+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC4		((uint)0x2b+CPM_IRQ_OFFSET)
+
+void m82xx_pci_init_irq(void);
+void mpc82xx_ads_show_cpuinfo(struct seq_file*);
+void m82xx_calibrate_decr(void);
+
+#endif /* __MACH_ADS8260_DEFS */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 5fe7b7f..0975e94 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -5,6 +5,13 @@
 	prompt "Machine Type"
 	default MPC834x_SYS
 
+config MPC832x_MDS
+	bool "Freescale MPC832x MDS"
+	select DEFAULT_UIMAGE
+	select QUICC_ENGINE
+	help
+	  This option enables support for the MPC832x MDS evaluation board.
+
 config MPC834x_SYS
 	bool "Freescale MPC834x SYS"
 	select DEFAULT_UIMAGE
@@ -27,6 +34,12 @@
 
 endchoice
 
+config PPC_MPC832x
+	bool
+	select PPC_UDBG_16550
+	select PPC_INDIRECT_PCI
+	default y if MPC832x_MDS
+
 config MPC834x
 	bool
 	select PPC_UDBG_16550
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
new file mode 100644
index 0000000..54dea9d4
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Description:
+ * MPC832xE MDS board specific routines.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/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/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+
+#include "mpc83xx.h"
+#include "mpc832x_mds.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+static u8 *bcsr_regs = NULL;
+
+u8 *get_bcsr(void)
+{
+	return bcsr_regs;
+}
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init mpc832x_sys_setup_arch(void)
+{
+	struct device_node *np;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc832x_sys_setup_arch()", 0);
+
+	np = of_find_node_by_type(NULL, "cpu");
+	if (np != 0) {
+		unsigned int *fp =
+		    (int *)get_property(np, "clock-frequency", NULL);
+		if (fp != 0)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+		of_node_put(np);
+	}
+
+	/* Map BCSR area */
+	np = of_find_node_by_name(NULL, "bcsr");
+	if (np != 0) {
+		struct resource res;
+
+		of_address_to_resource(np, 0, &res);
+		bcsr_regs = ioremap(res.start, res.end - res.start +1);
+		of_node_put(np);
+	}
+
+#ifdef CONFIG_PCI
+	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+		add_bridge(np);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef CONFIG_QUICC_ENGINE
+	qe_reset();
+
+	if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+		par_io_init(np);
+		of_node_put(np);
+
+		for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
+			par_io_of_config(np);
+	}
+
+	if ((np = of_find_compatible_node(NULL, "network", "ucc_geth"))
+			!= NULL){
+		/* Reset the Ethernet PHY */
+		bcsr_regs[9] &= ~0x20;
+		udelay(1000);
+		bcsr_regs[9] |= 0x20;
+		iounmap(bcsr_regs);
+		of_node_put(np);
+	}
+
+#endif				/* CONFIG_QUICC_ENGINE */
+
+#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_HDA1;
+#endif
+}
+
+void __init mpc832x_sys_init_IRQ(void)
+{
+
+	struct device_node *np;
+
+	np = of_find_node_by_type(NULL, "ipic");
+	if (!np)
+		return;
+
+	ipic_init(np, 0);
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	ipic_set_default_priority();
+	of_node_put(np);
+
+#ifdef CONFIG_QUICC_ENGINE
+	np = of_find_node_by_type(NULL, "qeic");
+	if (!np)
+		return;
+
+	qe_ic_init(np, 0);
+	of_node_put(np);
+#endif				/* CONFIG_QUICC_ENGINE */
+}
+
+#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+extern ulong ds1374_get_rtc_time(void);
+extern int ds1374_set_rtc_time(ulong);
+
+static int __init mpc832x_rtc_hookup(void)
+{
+	struct timespec tv;
+
+	ppc_md.get_rtc_time = ds1374_get_rtc_time;
+	ppc_md.set_rtc_time = ds1374_set_rtc_time;
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = (ppc_md.get_rtc_time) ();
+	do_settimeofday(&tv);
+
+	return 0;
+}
+
+late_initcall(mpc832x_rtc_hookup);
+#endif
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc832x_sys_probe(void)
+{
+	char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+					  "model", NULL);
+
+	if (model == NULL)
+		return 0;
+	if (strcmp(model, "MPC8323EMDS"))
+		return 0;
+
+	DBG("%s found\n", model);
+
+	return 1;
+}
+
+define_machine(mpc832x_mds) {
+	.name 		= "MPC832x MDS",
+	.probe 		= mpc832x_sys_probe,
+	.setup_arch 	= mpc832x_sys_setup_arch,
+	.init_IRQ 	= mpc832x_sys_init_IRQ,
+	.get_irq 	= ipic_get_irq,
+	.restart 	= mpc83xx_restart,
+	.time_init 	= mpc83xx_time_init,
+	.calibrate_decr	= generic_calibrate_decr,
+	.progress 	= udbg_progress,
+};
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h
new file mode 100644
index 0000000..a495889
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Description:
+ * MPC832x MDS board specific header.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __MACH_MPC832x_MDS_H__
+#define __MACH_MPC832x_MDS_H__
+
+extern u8 *get_bcsr(void);
+
+#endif				/* __MACH_MPC832x_MDS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 8c676d7..5446bab 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -11,7 +11,6 @@
  * option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
new file mode 100644
index 0000000..c019190
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Li Yang <LeoLi@freescale.com>
+ *	   Yin Olivia <Hong-hua.Yin@freescale.com>
+ *
+ * Description:
+ * MPC8360E MDS PB board specific routines.
+ *
+ * Changelog:
+ * Jun 21, 2006	Initial version
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/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/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+
+#include "mpc83xx.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+static u8 *bcsr_regs = NULL;
+
+u8 *get_bcsr(void)
+{
+	return bcsr_regs;
+}
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init mpc8360_sys_setup_arch(void)
+{
+	struct device_node *np;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mpc8360_sys_setup_arch()", 0);
+
+	np = of_find_node_by_type(NULL, "cpu");
+	if (np != 0) {
+		const unsigned int *fp =
+		    get_property(np, "clock-frequency", NULL);
+		if (fp != 0)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+		of_node_put(np);
+	}
+
+	/* Map BCSR area */
+	np = of_find_node_by_name(NULL, "bcsr");
+	if (np != 0) {
+		struct resource res;
+
+		of_address_to_resource(np, 0, &res);
+		bcsr_regs = ioremap(res.start, res.end - res.start +1);
+		of_node_put(np);
+	}
+
+#ifdef CONFIG_PCI
+	for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+		add_bridge(np);
+
+	ppc_md.pci_swizzle = common_swizzle;
+	ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef CONFIG_QUICC_ENGINE
+	qe_reset();
+
+	if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+		par_io_init(np);
+		of_node_put(np);
+
+		for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
+			par_io_of_config(np);
+	}
+
+	if ((np = of_find_compatible_node(NULL, "network", "ucc_geth"))
+			!= NULL){
+		/* Reset the Ethernet PHY */
+		bcsr_regs[9] &= ~0x20;
+		udelay(1000);
+		bcsr_regs[9] |= 0x20;
+		iounmap(bcsr_regs);
+		of_node_put(np);
+	}
+
+#endif				/* CONFIG_QUICC_ENGINE */
+
+#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_HDA1;
+#endif
+}
+
+void __init mpc8360_sys_init_IRQ(void)
+{
+
+	struct device_node *np;
+
+	np = of_find_node_by_type(NULL, "ipic");
+	if (!np)
+		return;
+
+	ipic_init(np, 0);
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	ipic_set_default_priority();
+	of_node_put(np);
+
+#ifdef CONFIG_QUICC_ENGINE
+	np = of_find_node_by_type(NULL, "qeic");
+	if (!np)
+		return;
+
+	qe_ic_init(np, 0);
+	of_node_put(np);
+#endif				/* CONFIG_QUICC_ENGINE */
+}
+
+#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+extern ulong ds1374_get_rtc_time(void);
+extern int ds1374_set_rtc_time(ulong);
+
+static int __init mpc8360_rtc_hookup(void)
+{
+	struct timespec tv;
+
+	ppc_md.get_rtc_time = ds1374_get_rtc_time;
+	ppc_md.set_rtc_time = ds1374_set_rtc_time;
+
+	tv.tv_nsec = 0;
+	tv.tv_sec = (ppc_md.get_rtc_time) ();
+	do_settimeofday(&tv);
+
+	return 0;
+}
+
+late_initcall(mpc8360_rtc_hookup);
+#endif
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc8360_sys_probe(void)
+{
+	char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+					  "model", NULL);
+	if (model == NULL)
+		return 0;
+	if (strcmp(model, "MPC8360EPB"))
+		return 0;
+
+	DBG("MPC8360EMDS-PB found\n");
+
+	return 1;
+}
+
+define_machine(mpc8360_sys) {
+	.name 		= "MPC8360E PB",
+	.probe 		= mpc8360_sys_probe,
+	.setup_arch 	= mpc8360_sys_setup_arch,
+	.init_IRQ 	= mpc8360_sys_init_IRQ,
+	.get_irq 	= ipic_get_irq,
+	.restart 	= mpc83xx_restart,
+	.time_init 	= mpc83xx_time_init,
+	.calibrate_decr	= generic_calibrate_decr,
+	.progress 	= udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.h b/arch/powerpc/platforms/85xx/mpc85xx_ads.h
index effcbf7..46c3532 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.h
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.h
@@ -18,7 +18,6 @@
 #ifndef __MACH_MPC85XXADS_H
 #define __MACH_MPC85XXADS_H
 
-#include <linux/config.h>
 #include <linux/initrd.h>
 #include <sysdev/fsl_soc.h>
 
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 4c1fede..193a5d7 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -11,7 +11,6 @@
  * option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 3f3859d..2f194ba 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -6,8 +6,6 @@
  * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
  */
 
-
-#include <linux/config.h>
 #include <linux/percpu.h>
 #include <linux/types.h>
 
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 6b57a47..6cc59e0 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -21,6 +21,12 @@
  * 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.
+ *
+ * TODO:
+ * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers
+ *   vs node numbers in the setup code
+ * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from
+ *   a non-active node to the active node)
  */
 
 #include <linux/interrupt.h>
@@ -44,24 +50,25 @@
 	u8 target_id;
 	u8 eoi_stack[16];
 	int eoi_ptr;
-	struct irq_host *host;
+	struct device_node *node;
 };
 
 static DEFINE_PER_CPU(struct iic, iic);
 #define IIC_NODE_COUNT	2
-static struct irq_host *iic_hosts[IIC_NODE_COUNT];
+static struct irq_host *iic_host;
 
 /* Convert between "pending" bits and hw irq number */
 static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
 {
 	unsigned char unit = bits.source & 0xf;
+	unsigned char node = bits.source >> 4;
+	unsigned char class = bits.class & 3;
 
+	/* Decode IPIs */
 	if (bits.flags & CBE_IIC_IRQ_IPI)
-		return IIC_IRQ_IPI0 | (bits.prio >> 4);
-	else if (bits.class <= 3)
-		return (bits.class << 4) | unit;
+		return IIC_IRQ_TYPE_IPI | (bits.prio >> 4);
 	else
-		return IIC_IRQ_INVALID;
+		return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit;
 }
 
 static void iic_mask(unsigned int irq)
@@ -86,21 +93,70 @@
 	.eoi = iic_eoi,
 };
 
+
+static void iic_ioexc_eoi(unsigned int irq)
+{
+}
+
+static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc,
+			    struct pt_regs *regs)
+{
+	struct cbe_iic_regs *node_iic = desc->handler_data;
+	unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC;
+	unsigned long bits, ack;
+	int cascade;
+
+	for (;;) {
+		bits = in_be64(&node_iic->iic_is);
+		if (bits == 0)
+			break;
+		/* pre-ack edge interrupts */
+		ack = bits & IIC_ISR_EDGE_MASK;
+		if (ack)
+			out_be64(&node_iic->iic_is, ack);
+		/* handle them */
+		for (cascade = 63; cascade >= 0; cascade--)
+			if (bits & (0x8000000000000000UL >> cascade)) {
+				unsigned int cirq =
+					irq_linear_revmap(iic_host,
+							  base | cascade);
+				if (cirq != NO_IRQ)
+					generic_handle_irq(cirq, regs);
+			}
+		/* post-ack level interrupts */
+		ack = bits & ~IIC_ISR_EDGE_MASK;
+		if (ack)
+			out_be64(&node_iic->iic_is, ack);
+	}
+	desc->chip->eoi(irq);
+}
+
+
+static struct irq_chip iic_ioexc_chip = {
+	.typename = " CELL-IOEX",
+	.mask = iic_mask,
+	.unmask = iic_unmask,
+	.eoi = iic_ioexc_eoi,
+};
+
 /* Get an IRQ number from the pending state register of the IIC */
 static unsigned int iic_get_irq(struct pt_regs *regs)
 {
 	struct cbe_iic_pending_bits pending;
 	struct iic *iic;
+	unsigned int virq;
 
 	iic = &__get_cpu_var(iic);
 	*(unsigned long *) &pending =
 		in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
+	if (!(pending.flags & CBE_IIC_IRQ_VALID))
+		return NO_IRQ;
+	virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending));
+	if (virq == NO_IRQ)
+		return NO_IRQ;
 	iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
 	BUG_ON(iic->eoi_ptr > 15);
-	if (pending.flags & CBE_IIC_IRQ_VALID)
-		return irq_linear_revmap(iic->host,
-					 iic_pending_to_hwnum(pending));
-	return NO_IRQ;
+	return virq;
 }
 
 #ifdef CONFIG_SMP
@@ -108,12 +164,7 @@
 /* Use the highest interrupt priorities for IPI */
 static inline int iic_ipi_to_irq(int ipi)
 {
-	return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi;
-}
-
-static inline int iic_irq_to_ipi(int irq)
-{
-	return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0);
+	return IIC_IRQ_TYPE_IPI + 0xf - ipi;
 }
 
 void iic_setup_cpu(void)
@@ -123,7 +174,7 @@
 
 void iic_cause_IPI(int cpu, int mesg)
 {
-	out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
+	out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4);
 }
 
 u8 iic_get_target_id(int cpu)
@@ -134,9 +185,7 @@
 
 struct irq_host *iic_get_irq_host(int node)
 {
-	if (node < 0 || node >= IIC_NODE_COUNT)
-		return NULL;
-	return iic_hosts[node];
+	return iic_host;
 }
 EXPORT_SYMBOL_GPL(iic_get_irq_host);
 
@@ -149,34 +198,20 @@
 
 	return IRQ_HANDLED;
 }
-
 static void iic_request_ipi(int ipi, const char *name)
 {
-	int node, virq;
+	int virq;
 
-	for (node = 0; node < IIC_NODE_COUNT; node++) {
-		char *rname;
-		if (iic_hosts[node] == NULL)
-			continue;
-		virq = irq_create_mapping(iic_hosts[node],
-					  iic_ipi_to_irq(ipi));
-		if (virq == NO_IRQ) {
-			printk(KERN_ERR
-			       "iic: failed to map IPI %s on node %d\n",
-			       name, node);
-			continue;
-		}
-		rname = kzalloc(strlen(name) + 16, GFP_KERNEL);
-		if (rname)
-			sprintf(rname, "%s node %d", name, node);
-		else
-			rname = (char *)name;
-		if (request_irq(virq, iic_ipi_action, IRQF_DISABLED,
-				rname, (void *)(long)ipi))
-			printk(KERN_ERR
-			       "iic: failed to request IPI %s on node %d\n",
-			       name, node);
+	virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi));
+	if (virq == NO_IRQ) {
+		printk(KERN_ERR
+		       "iic: failed to map IPI %s\n", name);
+		return;
 	}
+	if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name,
+			(void *)(long)ipi))
+		printk(KERN_ERR
+		       "iic: failed to request IPI %s\n", name);
 }
 
 void iic_request_IPIs(void)
@@ -193,16 +228,24 @@
 
 static int iic_host_match(struct irq_host *h, struct device_node *node)
 {
-	return h->host_data != NULL && node == h->host_data;
+	return device_is_compatible(node,
+				    "IBM,CBEA-Internal-Interrupt-Controller");
 }
 
 static int iic_host_map(struct irq_host *h, unsigned int virq,
 			irq_hw_number_t hw)
 {
-	if (hw < IIC_IRQ_IPI0)
-		set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
-	else
+	switch (hw & IIC_IRQ_TYPE_MASK) {
+	case IIC_IRQ_TYPE_IPI:
 		set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq);
+		break;
+	case IIC_IRQ_TYPE_IOEXC:
+		set_irq_chip_and_handler(virq, &iic_ioexc_chip,
+					 handle_fasteoi_irq);
+		break;
+	default:
+		set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
+	}
 	return 0;
 }
 
@@ -211,11 +254,39 @@
 			   irq_hw_number_t *out_hwirq, unsigned int *out_flags)
 
 {
-	/* Currently, we don't translate anything. That needs to be fixed as
-	 * we get better defined device-trees. iic interrupts have to be
-	 * explicitely mapped by whoever needs them
-	 */
-	return -ENODEV;
+	unsigned int node, ext, unit, class;
+	const u32 *val;
+
+	if (!device_is_compatible(ct,
+				     "IBM,CBEA-Internal-Interrupt-Controller"))
+		return -ENODEV;
+	if (intsize != 1)
+		return -ENODEV;
+	val = get_property(ct, "#interrupt-cells", NULL);
+	if (val == NULL || *val != 1)
+		return -ENODEV;
+
+	node = intspec[0] >> 24;
+	ext = (intspec[0] >> 16) & 0xff;
+	class = (intspec[0] >> 8) & 0xff;
+	unit = intspec[0] & 0xff;
+
+	/* Check if node is in supported range */
+	if (node > 1)
+		return -EINVAL;
+
+	/* Build up interrupt number, special case for IO exceptions */
+	*out_hwirq = (node << IIC_IRQ_NODE_SHIFT);
+	if (unit == IIC_UNIT_IIC && class == 1)
+		*out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext;
+	else
+		*out_hwirq |= IIC_IRQ_TYPE_NORMAL |
+			(class << IIC_IRQ_CLASS_SHIFT) | unit;
+
+	/* Dummy flags, ignored by iic code */
+	*out_flags = IRQ_TYPE_EDGE_RISING;
+
+	return 0;
 }
 
 static struct irq_host_ops iic_host_ops = {
@@ -225,7 +296,7 @@
 };
 
 static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
-				struct irq_host *host)
+				struct device_node *node)
 {
 	/* XXX FIXME: should locate the linux CPU number from the HW cpu
 	 * number properly. We are lucky for now
@@ -237,19 +308,19 @@
 
 	iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe);
 	iic->eoi_stack[0] = 0xff;
-	iic->host = host;
+	iic->node = of_node_get(node);
 	out_be64(&iic->regs->prio, 0);
 
-	printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n",
-	       hw_cpu, addr, iic->regs, iic->target_id);
+	printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n",
+	       hw_cpu, iic->target_id, node->full_name);
 }
 
 static int __init setup_iic(void)
 {
 	struct device_node *dn;
 	struct resource r0, r1;
-	struct irq_host *host;
-	int found = 0;
+	unsigned int node, cascade, found = 0;
+	struct cbe_iic_regs *node_iic;
 	const u32 *np;
 
 	for (dn = NULL;
@@ -269,19 +340,33 @@
 			of_node_put(dn);
 			return -ENODEV;
 		}
-		host = NULL;
-		if (found < IIC_NODE_COUNT) {
-			host = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
-					      IIC_SOURCE_COUNT,
-					      &iic_host_ops,
-					      IIC_IRQ_INVALID);
-			iic_hosts[found] = host;
-			BUG_ON(iic_hosts[found] == NULL);
-			iic_hosts[found]->host_data = of_node_get(dn);
-			found++;
-		}
-		init_one_iic(np[0], r0.start, host);
-		init_one_iic(np[1], r1.start, host);
+		found++;
+		init_one_iic(np[0], r0.start, dn);
+		init_one_iic(np[1], r1.start, dn);
+
+		/* Setup cascade for IO exceptions. XXX cleanup tricks to get
+		 * node vs CPU etc...
+		 * Note that we configure the IIC_IRR here with a hard coded
+		 * priority of 1. We might want to improve that later.
+		 */
+		node = np[0] >> 1;
+		node_iic = cbe_get_cpu_iic_regs(np[0]);
+		cascade = node << IIC_IRQ_NODE_SHIFT;
+		cascade |= 1 << IIC_IRQ_CLASS_SHIFT;
+		cascade |= IIC_UNIT_IIC;
+		cascade = irq_create_mapping(iic_host, cascade);
+		if (cascade == NO_IRQ)
+			continue;
+		set_irq_data(cascade, node_iic);
+		set_irq_chained_handler(cascade , iic_ioexc_cascade);
+		out_be64(&node_iic->iic_ir,
+			 (1 << 12)		/* priority */ |
+			 (node << 4)		/* dest node */ |
+			 IIC_UNIT_THREAD_0	/* route them to thread 0 */);
+		/* Flush pending (make sure it triggers if there is
+		 * anything pending
+		 */
+		out_be64(&node_iic->iic_is, 0xfffffffffffffffful);
 	}
 
 	if (found)
@@ -292,6 +377,12 @@
 
 void __init iic_init_IRQ(void)
 {
+	/* Setup an irq host data structure */
+	iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
+				  &iic_host_ops, IIC_IRQ_INVALID);
+	BUG_ON(iic_host == NULL);
+	irq_set_default_host(iic_host);
+
 	/* Discover and initialize iics */
 	if (setup_iic() < 0)
 		panic("IIC: Failed to initialize !\n");
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index 5560a92..9ba1d3c 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -2,48 +2,76 @@
 #define ASM_CELL_PIC_H
 #ifdef __KERNEL__
 /*
- * Mapping of IIC pending bits into per-node
- * interrupt numbers.
+ * Mapping of IIC pending bits into per-node interrupt numbers.
  *
- * IRQ     FF CC SS PP   FF CC SS PP	Description
+ * Interrupt numbers are in the range 0...0x1ff where the top bit
+ * (0x100) represent the source node. Only 2 nodes are supported with
+ * the current code though it's trivial to extend that if necessary using
+ * higher level bits
  *
- * 00-3f   80 02 +0 00 - 80 02 +0 3f	South Bridge
- * 00-3f   80 02 +b 00 - 80 02 +b 3f	South Bridge
- * 41-4a   80 00 +1 ** - 80 00 +a **	SPU Class 0
- * 51-5a   80 01 +1 ** - 80 01 +a **	SPU Class 1
- * 61-6a   80 02 +1 ** - 80 02 +a **	SPU Class 2
- * 70-7f   C0 ** ** 00 - C0 ** ** 0f	IPI
+ * The bottom 8 bits are split into 2 type bits and 6 data bits that
+ * depend on the type:
  *
- *    F flags
- *    C class
- *    S source
- *    P Priority
- *    + node number
- *    * don't care
+ * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source
+ * 01 (0x40 | data) : IO exception. data is the exception number as
+ *                    defined by bit numbers in IIC_SR
+ * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority)
+ *                    and node is always 0 (IPIs are per-cpu, their source is
+ *                    not relevant)
+ * 11 (0xc0 | data) : reserved
  *
- * A node consists of a Cell Broadband Engine and an optional
- * south bridge device providing a maximum of 64 IRQs.
- * The south bridge may be connected to either IOIF0
- * or IOIF1.
- * Each SPE is represented as three IRQ lines, one per
- * interrupt class.
- * 16 IRQ numbers are reserved for inter processor
- * interruptions, although these are only used in the
- * range of the first node.
+ * In addition, interrupt number 0x80000000 is defined as always invalid
+ * (that is the node field is expected to never extend to move than 23 bits)
  *
- * This scheme needs 128 IRQ numbers per BIF node ID,
- * which means that with the total of 512 lines
- * available, we can have a maximum of four nodes.
  */
 
 enum {
-	IIC_IRQ_INVALID		= 0xff,
-	IIC_IRQ_MAX		= 0x3f,
-	IIC_IRQ_EXT_IOIF0	= 0x20,
-	IIC_IRQ_EXT_IOIF1	= 0x2b,
-	IIC_IRQ_IPI0		= 0x40,
-	IIC_NUM_IPIS    	= 0x10, /* IRQs reserved for IPI */
-	IIC_SOURCE_COUNT	= 0x50,
+	IIC_IRQ_INVALID		= 0x80000000u,
+	IIC_IRQ_NODE_MASK	= 0x100,
+	IIC_IRQ_NODE_SHIFT	= 8,
+	IIC_IRQ_MAX		= 0x1ff,
+	IIC_IRQ_TYPE_MASK	= 0xc0,
+	IIC_IRQ_TYPE_NORMAL	= 0x00,
+	IIC_IRQ_TYPE_IOEXC	= 0x40,
+	IIC_IRQ_TYPE_IPI	= 0x80,
+	IIC_IRQ_CLASS_SHIFT	= 4,
+	IIC_IRQ_CLASS_0		= 0x00,
+	IIC_IRQ_CLASS_1		= 0x10,
+	IIC_IRQ_CLASS_2		= 0x20,
+	IIC_SOURCE_COUNT	= 0x200,
+
+	/* Here are defined the various source/dest units. Avoid using those
+	 * definitions if you can, they are mostly here for reference
+	 */
+	IIC_UNIT_SPU_0		= 0x4,
+	IIC_UNIT_SPU_1		= 0x7,
+	IIC_UNIT_SPU_2		= 0x3,
+	IIC_UNIT_SPU_3		= 0x8,
+	IIC_UNIT_SPU_4		= 0x2,
+	IIC_UNIT_SPU_5		= 0x9,
+	IIC_UNIT_SPU_6		= 0x1,
+	IIC_UNIT_SPU_7		= 0xa,
+	IIC_UNIT_IOC_0		= 0x0,
+	IIC_UNIT_IOC_1		= 0xb,
+	IIC_UNIT_THREAD_0	= 0xe, /* target only */
+	IIC_UNIT_THREAD_1	= 0xf, /* target only */
+	IIC_UNIT_IIC		= 0xe, /* source only (IO exceptions) */
+
+	/* Base numbers for the external interrupts */
+	IIC_IRQ_EXT_IOIF0	=
+		IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0,
+	IIC_IRQ_EXT_IOIF1	=
+		IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1,
+
+	/* Base numbers for the IIC_ISR interrupts */
+	IIC_IRQ_IOEX_TMI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63,
+	IIC_IRQ_IOEX_PMI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62,
+	IIC_IRQ_IOEX_ATI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61,
+	IIC_IRQ_IOEX_MATBFI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60,
+	IIC_IRQ_IOEX_ELDI	= IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59,
+
+	/* Which bits in IIC_ISR are edge sensitive */
+	IIC_ISR_EDGE_MASK	= 0x4ul,
 };
 
 extern void iic_init_IRQ(void);
@@ -52,7 +80,6 @@
 extern void iic_setup_cpu(void);
 
 extern u8 iic_get_target_id(int cpu);
-extern struct irq_host *iic_get_irq_host(int node);
 
 extern void spider_init_IRQ(void);
 
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 033ad6e..0984c70 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -1,6 +1,5 @@
 #define DEBUG
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 742a032..608b1eb 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -243,7 +243,6 @@
 	const u32 *imap, *tmp;
 	int imaplen, intsize, unit;
 	struct device_node *iic;
-	struct irq_host *iic_host;
 
 #if 0 /* Enable that when we have a way to retreive the node as well */
 	/* First, we check wether we have a real "interrupts" in the device
@@ -289,11 +288,11 @@
 	 * the iic host from the iic OF node, but that way I'm still compatible
 	 * with really really old old firmwares for which we don't have a node
 	 */
-	iic_host = iic_get_irq_host(pic->node_id);
-	if (iic_host == NULL)
-		return NO_IRQ;
 	/* Manufacture an IIC interrupt number of class 2 */
-	virq = irq_create_mapping(iic_host, 0x20 | unit);
+	virq = irq_create_mapping(NULL,
+				  (pic->node_id << IIC_IRQ_NODE_SHIFT) |
+				  (2 << IIC_IRQ_CLASS_SHIFT) |
+				  unit);
 	if (virq == NO_IRQ)
 		printk(KERN_ERR "spider_pic: failed to map cascade !");
 	return virq;
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 0f5c8eb..f786803 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -568,24 +568,23 @@
 /* This function shall be abstracted for HV platforms */
 static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
 {
-	struct irq_host *host;
 	unsigned int isrc;
 	const u32 *tmp;
 
-	host = iic_get_irq_host(spu->node);
-	if (host == NULL)
-		return -ENODEV;
-
-	/* Get the interrupt source from the device-tree */
+	/* Get the interrupt source unit from the device-tree */
 	tmp = get_property(np, "isrc", NULL);
 	if (!tmp)
 		return -ENODEV;
-	spu->isrc = isrc = tmp[0];
+	isrc = tmp[0];
+
+	/* Add the node number */
+	isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
+	spu->isrc = isrc;
 
 	/* Now map interrupts of all 3 classes */
-	spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc);
-	spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc);
-	spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc);
+	spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
+	spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
+	spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
 
 	/* Right now, we only fail if class 2 failed */
 	return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index e4f2b9d..cb6f084 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -18,7 +18,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 3eb1206..4aa165e 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -262,14 +262,6 @@
 	mf_display_src(0xC9000200);
 }
 
-void pcibios_fixup_bus(struct pci_bus *PciBus)
-{
-}
-
-void pcibios_fixup_resources(struct pci_dev *pdev)
-{
-}
-
 /*
  * Look down the chain to find the matching Device Device
  */
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 7f19530..a0ff7ba 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -649,15 +649,21 @@
 void __init iSeries_init_IRQ(void) { }
 #endif
 
+/*
+ * iSeries has no legacy IO, anything calling this function has to
+ * fail or bad things will happen
+ */
+static int iseries_check_legacy_ioport(unsigned int baseport)
+{
+	return -ENODEV;
+}
+
 static int __init iseries_probe(void)
 {
 	unsigned long root = of_get_flat_dt_root();
 	if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
 		return 0;
 
-	powerpc_firmware_features |= FW_FEATURE_ISERIES;
-	powerpc_firmware_features |= FW_FEATURE_LPAR;
-
 	hpte_init_iSeries();
 
 	return 1;
@@ -680,6 +686,7 @@
 	.calibrate_decr	= generic_calibrate_decr,
 	.progress	= iSeries_progress,
 	.probe		= iseries_probe,
+	.check_legacy_ioport	= iseries_check_legacy_ioport,
 	/* XXX Implement enable_pmcs for iSeries */
 };
 
@@ -687,6 +694,9 @@
 {
 	unsigned long phys_mem_size;
 
+	powerpc_firmware_features |= FW_FEATURE_ISERIES;
+	powerpc_firmware_features |= FW_FEATURE_LPAR;
+
 	iSeries_fixup_klimit();
 
 	/*
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 6284826..106896c 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -22,7 +22,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
diff --git a/arch/powerpc/platforms/pasemi/time.c b/arch/powerpc/platforms/pasemi/time.c
index 9bd410b..fa54351 100644
--- a/arch/powerpc/platforms/pasemi/time.c
+++ b/arch/powerpc/platforms/pasemi/time.c
@@ -17,7 +17,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/config.h>
 #include <linux/time.h>
 
 #include <asm/time.h>
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index ce1a235..379db05 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -111,8 +111,6 @@
 	pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
 			  PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
 
-
-	/* Setup for 57600 8N1 */
 	if (ch == ch_a)
 		addr += 0x20;
 	sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
@@ -125,9 +123,21 @@
 		x = in_8(sccc);
 	out_8(sccc, 0x09);		/* reset A or B side */
 	out_8(sccc, 0xc0);
+
+	/* If SCC was the OF output port, read the BRG value, else
+	 * Setup for 57600 8N1
+	 */
+	if (ch_def != NULL) {
+		out_8(sccc, 13);
+		scc_inittab[1] = in_8(sccc);
+		out_8(sccc, 12);
+		scc_inittab[3] = in_8(sccc);
+	}
+
 	for (i = 0; i < sizeof(scc_inittab); ++i)
 		out_8(sccc, scc_inittab[i]);
 
+
 	udbg_putc = udbg_scc_putc;
 	udbg_getc = udbg_scc_getc;
 	udbg_getc_poll = udbg_scc_getc_poll;
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 43dbf73..f82b13e 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -180,7 +180,7 @@
 
 	cascade_irq = irq_of_parse_and_map(cascade, 0);
 	if (cascade == NO_IRQ) {
-		printk(KERN_ERR "xics: failed to map cascade interrupt");
+		printk(KERN_ERR "mpic: failed to map cascade interrupt");
 		return;
 	}
 
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index f15f4d78..91f052d 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,6 +12,7 @@
 obj-$(CONFIG_FSL_SOC)		+= fsl_soc.o
 obj-$(CONFIG_PPC_TODC)		+= todc.o
 obj-$(CONFIG_TSI108_BRIDGE)	+= tsi108_pci.o tsi108_dev.o
+obj-$(CONFIG_QUICC_ENGINE)	+= qe_lib/
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_PPC_I8259)		+= i8259.o
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
index 5175299..28b0189 100644
--- a/arch/powerpc/sysdev/cpm2_pic.c
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -147,7 +147,7 @@
 	.end = cpm2_end_irq,
 };
 
-int cpm2_get_irq(struct pt_regs *regs)
+unsigned int cpm2_get_irq(struct pt_regs *regs)
 {
 	int irq;
 	unsigned long bits;
diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h
index d63e45d..3c513e5 100644
--- a/arch/powerpc/sysdev/cpm2_pic.h
+++ b/arch/powerpc/sysdev/cpm2_pic.h
@@ -3,7 +3,7 @@
 
 extern intctl_cpm2_t *cpm2_intctl;
 
-extern int cpm2_get_irq(struct pt_regs *regs);
+extern unsigned int cpm2_get_irq(struct pt_regs *regs);
 
 extern void cpm2_pic_init(struct device_node*);
 
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 022ed27..7d759f1 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -37,6 +37,7 @@
 #include <asm/cpm2.h>
 
 extern void init_fcc_ioports(struct fs_platform_info*);
+extern void init_scc_ioports(struct fs_uart_platform_info*);
 static phys_addr_t immrbase = -1;
 
 phys_addr_t get_immrbase(void)
@@ -566,7 +567,7 @@
 		struct resource r[4];
 		struct device_node *phy, *mdio;
 		struct fs_platform_info fs_enet_data;
-		const unsigned int *id, *phy_addr;
+		const unsigned int *id, *phy_addr, phy_irq;
 		const void *mac_addr;
 		const phandle *ph;
 		const char *model;
@@ -588,6 +589,7 @@
 		if (ret)
 			goto err;
 		r[2].name = fcc_regs_c;
+		fs_enet_data.fcc_regs_c = r[2].start;
 
 		r[3].start = r[3].end = irq_of_parse_and_map(np, 0);
 		r[3].flags = IORESOURCE_IRQ;
@@ -620,6 +622,8 @@
 		phy_addr = get_property(phy, "reg", NULL);
 		fs_enet_data.phy_addr = *phy_addr;
 
+		phy_irq = get_property(phy, "interrupts", NULL);
+
 		id = get_property(np, "device-id", NULL);
 		fs_enet_data.fs_no = *id;
 		strcpy(fs_enet_data.fs_type, model);
@@ -637,6 +641,7 @@
 
 		if (strstr(model, "FCC")) {
 			int fcc_index = *id - 1;
+			unsigned char* mdio_bb_prop;
 
 			fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0);
 			fs_enet_data.rx_ring = 32;
@@ -652,14 +657,57 @@
 							(u32)res.start, fs_enet_data.phy_addr);
 			fs_enet_data.bus_id = (char*)&bus_id[(*id)];
 			fs_enet_data.init_ioports = init_fcc_ioports;
-		}
 
-		of_node_put(phy);
-		of_node_put(mdio);
+			mdio_bb_prop = get_property(phy, "bitbang", NULL);
+			if (mdio_bb_prop) {
+				struct platform_device *fs_enet_mdio_bb_dev;
+				struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
 
-		ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
-					     sizeof(struct
-						    fs_platform_info));
+				fs_enet_mdio_bb_dev =
+					platform_device_register_simple("fsl-bb-mdio",
+							i, NULL, 0);
+				memset(&fs_enet_mdio_bb_data, 0,
+						sizeof(struct fs_mii_bb_platform_info));
+				fs_enet_mdio_bb_data.mdio_dat.bit =
+					mdio_bb_prop[0];
+				fs_enet_mdio_bb_data.mdio_dir.bit =
+					mdio_bb_prop[1];
+				fs_enet_mdio_bb_data.mdc_dat.bit =
+					mdio_bb_prop[2];
+				fs_enet_mdio_bb_data.mdio_port =
+					mdio_bb_prop[3];
+				fs_enet_mdio_bb_data.mdc_port =
+					mdio_bb_prop[4];
+				fs_enet_mdio_bb_data.delay =
+					mdio_bb_prop[5];
+
+				fs_enet_mdio_bb_data.irq[0] = phy_irq[0];
+				fs_enet_mdio_bb_data.irq[1] = -1;
+				fs_enet_mdio_bb_data.irq[2] = -1;
+				fs_enet_mdio_bb_data.irq[3] = phy_irq[0];
+				fs_enet_mdio_bb_data.irq[31] = -1;
+
+				fs_enet_mdio_bb_data.mdio_dat.offset =
+					(u32)&cpm2_immr->im_ioport.iop_pdatc;
+				fs_enet_mdio_bb_data.mdio_dir.offset =
+					(u32)&cpm2_immr->im_ioport.iop_pdirc;
+				fs_enet_mdio_bb_data.mdc_dat.offset =
+					(u32)&cpm2_immr->im_ioport.iop_pdatc;
+
+				ret = platform_device_add_data(
+						fs_enet_mdio_bb_dev,
+						&fs_enet_mdio_bb_data,
+						sizeof(struct fs_mii_bb_platform_info));
+				if (ret)
+					goto unreg;
+			}
+			
+			of_node_put(phy);
+			of_node_put(mdio);
+
+			ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
+						     sizeof(struct
+							    fs_platform_info));
 		if (ret)
 			goto unreg;
 	}
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index 723972b..3ee03a9 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -341,7 +341,7 @@
 		u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
 		if (id == PCI_CAP_ID_HT) {
 			id = readb(devbase + pos + 3);
-			if (id == 0x80)
+			if (id == HT_CAPTYPE_IRQ)
 				break;
 		}
 	}
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
new file mode 100644
index 0000000..a725e80
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -0,0 +1,30 @@
+#
+# QE Communication options
+#
+
+menu "QE Options"
+	depends on QUICC_ENGINE
+
+config UCC_SLOW
+	bool "UCC Slow Protocols Support"
+	default n
+	select UCC
+	help
+	  This option provides qe_lib support to UCC slow
+	  protocols: UART, BISYNC, QMC
+
+config UCC_FAST
+	bool "UCC Fast Protocols Support"
+	default n
+	select UCC
+	select UCC_SLOW
+	help
+	  This option provides qe_lib support to UCC fast
+	  protocols: HDLC, Ethernet, ATM, transparent
+
+config UCC
+	bool
+	default y if UCC_FAST || UCC_SLOW
+
+endmenu
+
diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile
new file mode 100644
index 0000000..874fe1a
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux ppc-specific parts of QE
+#
+obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o
+
+obj-$(CONFIG_UCC)	+= ucc.o
+obj-$(CONFIG_UCC_SLOW)	+= ucc_slow.o
+obj-$(CONFIG_UCC_FAST)	+= ucc_fast.o
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
new file mode 100644
index 0000000..2bae632
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net)
+ *
+ * Description:
+ * General Purpose functions for the global management of the
+ * QUICC Engine (QE).
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+#include <asm/prom.h>
+#include <asm/rheap.h>
+
+static void qe_snums_init(void);
+static void qe_muram_init(void);
+static int qe_sdma_init(void);
+
+static DEFINE_SPINLOCK(qe_lock);
+
+/* QE snum state */
+enum qe_snum_state {
+	QE_SNUM_STATE_USED,
+	QE_SNUM_STATE_FREE
+};
+
+/* QE snum */
+struct qe_snum {
+	u8 num;
+	enum qe_snum_state state;
+};
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+struct qe_immap *qe_immr = NULL;
+EXPORT_SYMBOL(qe_immr);
+
+static struct qe_snum snums[QE_NUM_OF_SNUM];	/* Dynamically allocated SNUMs */
+
+static phys_addr_t qebase = -1;
+
+phys_addr_t get_qe_base(void)
+{
+	struct device_node *qe;
+
+	if (qebase != -1)
+		return qebase;
+
+	qe = of_find_node_by_type(NULL, "qe");
+	if (qe) {
+		unsigned int size;
+		const void *prop = get_property(qe, "reg", &size);
+		qebase = of_translate_address(qe, prop);
+		of_node_put(qe);
+	};
+
+	return qebase;
+}
+
+EXPORT_SYMBOL(get_qe_base);
+
+void qe_reset(void)
+{
+	if (qe_immr == NULL)
+		qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
+
+	qe_snums_init();
+
+	qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
+		     QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+	/* Reclaim the MURAM memory for our use. */
+	qe_muram_init();
+
+	if (qe_sdma_init())
+		panic("sdma init failed!");
+}
+
+int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
+{
+	unsigned long flags;
+	u8 mcn_shift = 0, dev_shift = 0;
+
+	spin_lock_irqsave(&qe_lock, flags);
+	if (cmd == QE_RESET) {
+		out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
+	} else {
+		if (cmd == QE_ASSIGN_PAGE) {
+			/* Here device is the SNUM, not sub-block */
+			dev_shift = QE_CR_SNUM_SHIFT;
+		} else if (cmd == QE_ASSIGN_RISC) {
+			/* Here device is the SNUM, and mcnProtocol is
+			 * e_QeCmdRiscAssignment value */
+			dev_shift = QE_CR_SNUM_SHIFT;
+			mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
+		} else {
+			if (device == QE_CR_SUBBLOCK_USB)
+				mcn_shift = QE_CR_MCN_USB_SHIFT;
+			else
+				mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
+		}
+
+		out_be32(&qe_immr->cp.cecdr,
+			 immrbar_virt_to_phys((void *)cmd_input));
+		out_be32(&qe_immr->cp.cecr,
+			 (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
+			  mcn_protocol << mcn_shift));
+	}
+
+	/* wait for the QE_CR_FLG to clear */
+	while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
+		cpu_relax();
+	spin_unlock_irqrestore(&qe_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(qe_issue_cmd);
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * 16 BRGs, which can be connected to the QE channels or output
+ * as clocks. The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers). Documentation uses 1-based numbering.
+ */
+static unsigned int brg_clk = 0;
+
+unsigned int get_brg_clk(void)
+{
+	struct device_node *qe;
+	if (brg_clk)
+		return brg_clk;
+
+	qe = of_find_node_by_type(NULL, "qe");
+	if (qe) {
+		unsigned int size;
+		const u32 *prop = get_property(qe, "brg-frequency", &size);
+		brg_clk = *prop;
+		of_node_put(qe);
+	};
+	return brg_clk;
+}
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void qe_setbrg(u32 brg, u32 rate)
+{
+	volatile u32 *bp;
+	u32 divisor, tempval;
+	int div16 = 0;
+
+	bp = &qe_immr->brg.brgc1;
+	bp += brg;
+
+	divisor = (get_brg_clk() / rate);
+	if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
+		div16 = 1;
+		divisor /= 16;
+	}
+
+	tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
+	if (div16)
+		tempval |= QE_BRGC_DIV16;
+
+	out_be32(bp, tempval);
+}
+
+/* Initialize SNUMs (thread serial numbers) according to
+ * QE Module Control chapter, SNUM table
+ */
+static void qe_snums_init(void)
+{
+	int i;
+	static const u8 snum_init[] = {
+		0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
+		0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
+		0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
+		0xD8, 0xD9, 0xE8, 0xE9,
+	};
+
+	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+		snums[i].num = snum_init[i];
+		snums[i].state = QE_SNUM_STATE_FREE;
+	}
+}
+
+int qe_get_snum(void)
+{
+	unsigned long flags;
+	int snum = -EBUSY;
+	int i;
+
+	spin_lock_irqsave(&qe_lock, flags);
+	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+		if (snums[i].state == QE_SNUM_STATE_FREE) {
+			snums[i].state = QE_SNUM_STATE_USED;
+			snum = snums[i].num;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&qe_lock, flags);
+
+	return snum;
+}
+EXPORT_SYMBOL(qe_get_snum);
+
+void qe_put_snum(u8 snum)
+{
+	int i;
+
+	for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+		if (snums[i].num == snum) {
+			snums[i].state = QE_SNUM_STATE_FREE;
+			break;
+		}
+	}
+}
+EXPORT_SYMBOL(qe_put_snum);
+
+static int qe_sdma_init(void)
+{
+	struct sdma *sdma = &qe_immr->sdma;
+	u32 sdma_buf_offset;
+
+	if (!sdma)
+		return -ENODEV;
+
+	/* allocate 2 internal temporary buffers (512 bytes size each) for
+	 * the SDMA */
+	sdma_buf_offset = qe_muram_alloc(512 * 2, 64);
+	if (IS_MURAM_ERR(sdma_buf_offset))
+		return -ENOMEM;
+
+	out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
+	out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >>
+					QE_SDMR_CEN_SHIFT)));
+
+	return 0;
+}
+
+/*
+ * muram_alloc / muram_free bits.
+ */
+static DEFINE_SPINLOCK(qe_muram_lock);
+
+/* 16 blocks should be enough to satisfy all requests
+ * until the memory subsystem goes up... */
+static rh_block_t qe_boot_muram_rh_block[16];
+static rh_info_t qe_muram_info;
+
+static void qe_muram_init(void)
+{
+	struct device_node *np;
+	u32 address;
+	u64 size;
+	unsigned int flags;
+
+	/* initialize the info header */
+	rh_init(&qe_muram_info, 1,
+		sizeof(qe_boot_muram_rh_block) /
+		sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
+
+	/* Attach the usable muram area */
+	/* XXX: This is a subset of the available muram. It
+	 * varies with the processor and the microcode patches activated.
+	 */
+	if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) {
+		address = *of_get_address(np, 0, &size, &flags);
+		of_node_put(np);
+		rh_attach_region(&qe_muram_info,
+			(void *)address, (int)size);
+	}
+}
+
+/* This function returns an index into the MURAM area.
+ */
+u32 qe_muram_alloc(u32 size, u32 align)
+{
+	void *start;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qe_muram_lock, flags);
+	start = rh_alloc_align(&qe_muram_info, size, align, "QE");
+	spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+	return (u32) start;
+}
+EXPORT_SYMBOL(qe_muram_alloc);
+
+int qe_muram_free(u32 offset)
+{
+	int ret;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qe_muram_lock, flags);
+	ret = rh_free(&qe_muram_info, (void *)offset);
+	spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(qe_muram_free);
+
+/* not sure if this is ever needed */
+u32 qe_muram_alloc_fixed(u32 offset, u32 size)
+{
+	void *start;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qe_muram_lock, flags);
+	start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc");
+	spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+	return (u32) start;
+}
+EXPORT_SYMBOL(qe_muram_alloc_fixed);
+
+void qe_muram_dump(void)
+{
+	rh_dump(&qe_muram_info);
+}
+EXPORT_SYMBOL(qe_muram_dump);
+
+void *qe_muram_addr(u32 offset)
+{
+	return (void *)&qe_immr->muram[offset];
+}
+EXPORT_SYMBOL(qe_muram_addr);
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
new file mode 100644
index 0000000..c229d07
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -0,0 +1,555 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/qe_ic.c
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc.  All rights reserved.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ * Based on code from Shlomi Gridish <gridish@freescale.com>
+ *
+ * QUICC ENGINE Interrupt Controller
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sysdev.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/qe_ic.h>
+
+#include "qe_ic.h"
+
+static DEFINE_SPINLOCK(qe_ic_lock);
+
+static struct qe_ic_info qe_ic_info[] = {
+	[1] = {
+	       .mask = 0x00008000,
+	       .mask_reg = QEIC_CIMR,
+	       .pri_code = 0,
+	       .pri_reg = QEIC_CIPWCC,
+	       },
+	[2] = {
+	       .mask = 0x00004000,
+	       .mask_reg = QEIC_CIMR,
+	       .pri_code = 1,
+	       .pri_reg = QEIC_CIPWCC,
+	       },
+	[3] = {
+	       .mask = 0x00002000,
+	       .mask_reg = QEIC_CIMR,
+	       .pri_code = 2,
+	       .pri_reg = QEIC_CIPWCC,
+	       },
+	[10] = {
+		.mask = 0x00000040,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 1,
+		.pri_reg = QEIC_CIPZCC,
+		},
+	[11] = {
+		.mask = 0x00000020,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 2,
+		.pri_reg = QEIC_CIPZCC,
+		},
+	[12] = {
+		.mask = 0x00000010,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 3,
+		.pri_reg = QEIC_CIPZCC,
+		},
+	[13] = {
+		.mask = 0x00000008,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 4,
+		.pri_reg = QEIC_CIPZCC,
+		},
+	[14] = {
+		.mask = 0x00000004,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 5,
+		.pri_reg = QEIC_CIPZCC,
+		},
+	[15] = {
+		.mask = 0x00000002,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 6,
+		.pri_reg = QEIC_CIPZCC,
+		},
+	[20] = {
+		.mask = 0x10000000,
+		.mask_reg = QEIC_CRIMR,
+		.pri_code = 3,
+		.pri_reg = QEIC_CIPRTA,
+		},
+	[25] = {
+		.mask = 0x00800000,
+		.mask_reg = QEIC_CRIMR,
+		.pri_code = 0,
+		.pri_reg = QEIC_CIPRTB,
+		},
+	[26] = {
+		.mask = 0x00400000,
+		.mask_reg = QEIC_CRIMR,
+		.pri_code = 1,
+		.pri_reg = QEIC_CIPRTB,
+		},
+	[27] = {
+		.mask = 0x00200000,
+		.mask_reg = QEIC_CRIMR,
+		.pri_code = 2,
+		.pri_reg = QEIC_CIPRTB,
+		},
+	[28] = {
+		.mask = 0x00100000,
+		.mask_reg = QEIC_CRIMR,
+		.pri_code = 3,
+		.pri_reg = QEIC_CIPRTB,
+		},
+	[32] = {
+		.mask = 0x80000000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 0,
+		.pri_reg = QEIC_CIPXCC,
+		},
+	[33] = {
+		.mask = 0x40000000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 1,
+		.pri_reg = QEIC_CIPXCC,
+		},
+	[34] = {
+		.mask = 0x20000000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 2,
+		.pri_reg = QEIC_CIPXCC,
+		},
+	[35] = {
+		.mask = 0x10000000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 3,
+		.pri_reg = QEIC_CIPXCC,
+		},
+	[36] = {
+		.mask = 0x08000000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 4,
+		.pri_reg = QEIC_CIPXCC,
+		},
+	[40] = {
+		.mask = 0x00800000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 0,
+		.pri_reg = QEIC_CIPYCC,
+		},
+	[41] = {
+		.mask = 0x00400000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 1,
+		.pri_reg = QEIC_CIPYCC,
+		},
+	[42] = {
+		.mask = 0x00200000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 2,
+		.pri_reg = QEIC_CIPYCC,
+		},
+	[43] = {
+		.mask = 0x00100000,
+		.mask_reg = QEIC_CIMR,
+		.pri_code = 3,
+		.pri_reg = QEIC_CIPYCC,
+		},
+};
+
+static inline u32 qe_ic_read(volatile __be32  __iomem * base, unsigned int reg)
+{
+	return in_be32(base + (reg >> 2));
+}
+
+static inline void qe_ic_write(volatile __be32  __iomem * base, unsigned int reg,
+			       u32 value)
+{
+	out_be32(base + (reg >> 2), value);
+}
+
+static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
+{
+	return irq_desc[virq].chip_data;
+}
+
+#define virq_to_hw(virq)	((unsigned int)irq_map[virq].hwirq)
+
+static void qe_ic_unmask_irq(unsigned int virq)
+{
+	struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+	unsigned int src = virq_to_hw(virq);
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&qe_ic_lock, flags);
+
+	temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+	qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+		    temp | qe_ic_info[src].mask);
+
+	spin_unlock_irqrestore(&qe_ic_lock, flags);
+}
+
+static void qe_ic_mask_irq(unsigned int virq)
+{
+	struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+	unsigned int src = virq_to_hw(virq);
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&qe_ic_lock, flags);
+
+	temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+	qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+		    temp & ~qe_ic_info[src].mask);
+
+	spin_unlock_irqrestore(&qe_ic_lock, flags);
+}
+
+static void qe_ic_mask_irq_and_ack(unsigned int virq)
+{
+	struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+	unsigned int src = virq_to_hw(virq);
+	unsigned long flags;
+	u32 temp;
+
+	spin_lock_irqsave(&qe_ic_lock, flags);
+
+	temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+	qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+		    temp & ~qe_ic_info[src].mask);
+
+	/* There is nothing to do for ack here, ack is handled in ISR */
+
+	spin_unlock_irqrestore(&qe_ic_lock, flags);
+}
+
+static struct irq_chip qe_ic_irq_chip = {
+	.typename = " QEIC  ",
+	.unmask = qe_ic_unmask_irq,
+	.mask = qe_ic_mask_irq,
+	.mask_ack = qe_ic_mask_irq_and_ack,
+};
+
+static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
+{
+	struct qe_ic *qe_ic = h->host_data;
+
+	/* Exact match, unless qe_ic node is NULL */
+	return qe_ic->of_node == NULL || qe_ic->of_node == node;
+}
+
+static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
+			  irq_hw_number_t hw)
+{
+	struct qe_ic *qe_ic = h->host_data;
+	struct irq_chip *chip;
+
+	if (qe_ic_info[hw].mask == 0) {
+		printk(KERN_ERR "Can't map reserved IRQ \n");
+		return -EINVAL;
+	}
+	/* Default chip */
+	chip = &qe_ic->hc_irq;
+
+	set_irq_chip_data(virq, qe_ic);
+	get_irq_desc(virq)->status |= IRQ_LEVEL;
+
+	set_irq_chip_and_handler(virq, chip, handle_level_irq);
+
+	return 0;
+}
+
+static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct,
+			    u32 * intspec, unsigned int intsize,
+			    irq_hw_number_t * out_hwirq,
+			    unsigned int *out_flags)
+{
+	*out_hwirq = intspec[0];
+	if (intsize > 1)
+		*out_flags = intspec[1];
+	else
+		*out_flags = IRQ_TYPE_NONE;
+	return 0;
+}
+
+static struct irq_host_ops qe_ic_host_ops = {
+	.match = qe_ic_host_match,
+	.map = qe_ic_host_map,
+	.xlate = qe_ic_host_xlate,
+};
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic, struct pt_regs *regs)
+{
+	int irq;
+
+	BUG_ON(qe_ic == NULL);
+
+	/* get the interrupt source vector. */
+	irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
+
+	if (irq == 0)
+		return NO_IRQ;
+
+	return irq_linear_revmap(qe_ic->irqhost, irq);
+}
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic, struct pt_regs *regs)
+{
+	int irq;
+
+	BUG_ON(qe_ic == NULL);
+
+	/* get the interrupt source vector. */
+	irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
+
+	if (irq == 0)
+		return NO_IRQ;
+
+	return irq_linear_revmap(qe_ic->irqhost, irq);
+}
+
+/* FIXME: We mask all the QE Low interrupts while handling.  We should
+ * let other interrupt come in, but BAD interrupts are generated */
+void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc,
+				struct pt_regs *regs)
+{
+	struct qe_ic *qe_ic = desc->handler_data;
+	struct irq_chip *chip = irq_desc[irq].chip;
+
+	unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic, regs);
+
+	chip->mask_ack(irq);
+	if (cascade_irq != NO_IRQ)
+		generic_handle_irq(cascade_irq, regs);
+	chip->unmask(irq);
+}
+
+/* FIXME: We mask all the QE High interrupts while handling.  We should
+ * let other interrupt come in, but BAD interrupts are generated */
+void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc,
+				 struct pt_regs *regs)
+{
+	struct qe_ic *qe_ic = desc->handler_data;
+	struct irq_chip *chip = irq_desc[irq].chip;
+
+	unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic, regs);
+
+	chip->mask_ack(irq);
+	if (cascade_irq != NO_IRQ)
+		generic_handle_irq(cascade_irq, regs);
+	chip->unmask(irq);
+}
+
+void __init qe_ic_init(struct device_node *node, unsigned int flags)
+{
+	struct qe_ic *qe_ic;
+	struct resource res;
+	u32 temp = 0, ret, high_active = 0;
+
+	qe_ic = alloc_bootmem(sizeof(struct qe_ic));
+	if (qe_ic == NULL)
+		return;
+
+	memset(qe_ic, 0, sizeof(struct qe_ic));
+	qe_ic->of_node = node ? of_node_get(node) : NULL;
+
+	qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
+					NR_QE_IC_INTS, &qe_ic_host_ops, 0);
+	if (qe_ic->irqhost == NULL) {
+		of_node_put(node);
+		return;
+	}
+
+	ret = of_address_to_resource(node, 0, &res);
+	if (ret)
+		return;
+
+	qe_ic->regs = ioremap(res.start, res.end - res.start + 1);
+
+	qe_ic->irqhost->host_data = qe_ic;
+	qe_ic->hc_irq = qe_ic_irq_chip;
+
+	qe_ic->virq_high = irq_of_parse_and_map(node, 0);
+	qe_ic->virq_low = irq_of_parse_and_map(node, 1);
+
+	if (qe_ic->virq_low == NO_IRQ) {
+		printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
+		return;
+	}
+
+	/* default priority scheme is grouped. If spread mode is    */
+	/* required, configure cicr accordingly.                    */
+	if (flags & QE_IC_SPREADMODE_GRP_W)
+		temp |= CICR_GWCC;
+	if (flags & QE_IC_SPREADMODE_GRP_X)
+		temp |= CICR_GXCC;
+	if (flags & QE_IC_SPREADMODE_GRP_Y)
+		temp |= CICR_GYCC;
+	if (flags & QE_IC_SPREADMODE_GRP_Z)
+		temp |= CICR_GZCC;
+	if (flags & QE_IC_SPREADMODE_GRP_RISCA)
+		temp |= CICR_GRTA;
+	if (flags & QE_IC_SPREADMODE_GRP_RISCB)
+		temp |= CICR_GRTB;
+
+	/* choose destination signal for highest priority interrupt */
+	if (flags & QE_IC_HIGH_SIGNAL) {
+		temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT);
+		high_active = 1;
+	}
+
+	qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+
+	set_irq_data(qe_ic->virq_low, qe_ic);
+	set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low);
+
+	if (qe_ic->virq_high != NO_IRQ) {
+		set_irq_data(qe_ic->virq_high, qe_ic);
+		set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high);
+	}
+
+	printk("QEIC (%d IRQ sources) at %p\n", NR_QE_IC_INTS, qe_ic->regs);
+}
+
+void qe_ic_set_highest_priority(unsigned int virq, int high)
+{
+	struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+	unsigned int src = virq_to_hw(virq);
+	u32 temp = 0;
+
+	temp = qe_ic_read(qe_ic->regs, QEIC_CICR);
+
+	temp &= ~CICR_HP_MASK;
+	temp |= src << CICR_HP_SHIFT;
+
+	temp &= ~CICR_HPIT_MASK;
+	temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT;
+
+	qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+}
+
+/* Set Priority level within its group, from 1 to 8 */
+int qe_ic_set_priority(unsigned int virq, unsigned int priority)
+{
+	struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+	unsigned int src = virq_to_hw(virq);
+	u32 temp;
+
+	if (priority > 8 || priority == 0)
+		return -EINVAL;
+	if (src > 127)
+		return -EINVAL;
+	if (qe_ic_info[src].pri_reg == 0)
+		return -EINVAL;
+
+	temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg);
+
+	if (priority < 4) {
+		temp &= ~(0x7 << (32 - priority * 3));
+		temp |= qe_ic_info[src].pri_code << (32 - priority * 3);
+	} else {
+		temp &= ~(0x7 << (24 - priority * 3));
+		temp |= qe_ic_info[src].pri_code << (24 - priority * 3);
+	}
+
+	qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp);
+
+	return 0;
+}
+
+/* Set a QE priority to use high irq, only priority 1~2 can use high irq */
+int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
+{
+	struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+	unsigned int src = virq_to_hw(virq);
+	u32 temp, control_reg = QEIC_CICNR, shift = 0;
+
+	if (priority > 2 || priority == 0)
+		return -EINVAL;
+
+	switch (qe_ic_info[src].pri_reg) {
+	case QEIC_CIPZCC:
+		shift = CICNR_ZCC1T_SHIFT;
+		break;
+	case QEIC_CIPWCC:
+		shift = CICNR_WCC1T_SHIFT;
+		break;
+	case QEIC_CIPYCC:
+		shift = CICNR_YCC1T_SHIFT;
+		break;
+	case QEIC_CIPXCC:
+		shift = CICNR_XCC1T_SHIFT;
+		break;
+	case QEIC_CIPRTA:
+		shift = CRICR_RTA1T_SHIFT;
+		control_reg = QEIC_CRICR;
+		break;
+	case QEIC_CIPRTB:
+		shift = CRICR_RTB1T_SHIFT;
+		control_reg = QEIC_CRICR;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	shift += (2 - priority) * 2;
+	temp = qe_ic_read(qe_ic->regs, control_reg);
+	temp &= ~(SIGNAL_MASK << shift);
+	temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift;
+	qe_ic_write(qe_ic->regs, control_reg, temp);
+
+	return 0;
+}
+
+static struct sysdev_class qe_ic_sysclass = {
+	set_kset_name("qe_ic"),
+};
+
+static struct sys_device device_qe_ic = {
+	.id = 0,
+	.cls = &qe_ic_sysclass,
+};
+
+static int __init init_qe_ic_sysfs(void)
+{
+	int rc;
+
+	printk(KERN_DEBUG "Registering qe_ic with sysfs...\n");
+
+	rc = sysdev_class_register(&qe_ic_sysclass);
+	if (rc) {
+		printk(KERN_ERR "Failed registering qe_ic sys class\n");
+		return -ENODEV;
+	}
+	rc = sysdev_register(&device_qe_ic);
+	if (rc) {
+		printk(KERN_ERR "Failed registering qe_ic sys device\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+subsys_initcall(init_qe_ic_sysfs);
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h
new file mode 100644
index 0000000..9a631ad
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h
@@ -0,0 +1,106 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/qe_ic.h
+ *
+ * QUICC ENGINE Interrupt Controller Header
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ * Based on code from Shlomi Gridish <gridish@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _POWERPC_SYSDEV_QE_IC_H
+#define _POWERPC_SYSDEV_QE_IC_H
+
+#include <asm/qe_ic.h>
+
+#define NR_QE_IC_INTS		64
+
+/* QE IC registers offset */
+#define QEIC_CICR		0x00
+#define QEIC_CIVEC		0x04
+#define QEIC_CRIPNR		0x08
+#define QEIC_CIPNR		0x0c
+#define QEIC_CIPXCC		0x10
+#define QEIC_CIPYCC		0x14
+#define QEIC_CIPWCC		0x18
+#define QEIC_CIPZCC		0x1c
+#define QEIC_CIMR		0x20
+#define QEIC_CRIMR		0x24
+#define QEIC_CICNR		0x28
+#define QEIC_CIPRTA		0x30
+#define QEIC_CIPRTB		0x34
+#define QEIC_CRICR		0x3c
+#define QEIC_CHIVEC		0x60
+
+/* Interrupt priority registers */
+#define CIPCC_SHIFT_PRI0	29
+#define CIPCC_SHIFT_PRI1	26
+#define CIPCC_SHIFT_PRI2	23
+#define CIPCC_SHIFT_PRI3	20
+#define CIPCC_SHIFT_PRI4	13
+#define CIPCC_SHIFT_PRI5	10
+#define CIPCC_SHIFT_PRI6	7
+#define CIPCC_SHIFT_PRI7	4
+
+/* CICR priority modes */
+#define CICR_GWCC		0x00040000
+#define CICR_GXCC		0x00020000
+#define CICR_GYCC		0x00010000
+#define CICR_GZCC		0x00080000
+#define CICR_GRTA		0x00200000
+#define CICR_GRTB		0x00400000
+#define CICR_HPIT_SHIFT		8
+#define CICR_HPIT_MASK		0x00000300
+#define CICR_HP_SHIFT		24
+#define CICR_HP_MASK		0x3f000000
+
+/* CICNR */
+#define CICNR_WCC1T_SHIFT	20
+#define CICNR_ZCC1T_SHIFT	28
+#define CICNR_YCC1T_SHIFT	12
+#define CICNR_XCC1T_SHIFT	4
+
+/* CRICR */
+#define CRICR_RTA1T_SHIFT	20
+#define CRICR_RTB1T_SHIFT	28
+
+/* Signal indicator */
+#define SIGNAL_MASK		3
+#define SIGNAL_HIGH		2
+#define SIGNAL_LOW		0
+
+struct qe_ic {
+	/* Control registers offset */
+	volatile u32 __iomem *regs;
+
+	/* The remapper for this QEIC */
+	struct irq_host *irqhost;
+
+	/* The "linux" controller struct */
+	struct irq_chip hc_irq;
+
+	/* The device node of the interrupt controller */
+	struct device_node *of_node;
+
+	/* VIRQ numbers of QE high/low irqs */
+	unsigned int virq_high;
+	unsigned int virq_low;
+};
+
+/*
+ * QE interrupt controller internal structure
+ */
+struct qe_ic_info {
+	u32	mask;	  /* location of this source at the QIMR register. */
+	u32	mask_reg; /* Mask register offset */
+	u8	pri_code; /* for grouped interrupts sources - the interrupt
+			     code as appears at the group priority register */
+	u32	pri_reg;  /* Group priority register offset */
+};
+
+#endif /* _POWERPC_SYSDEV_QE_IC_H */
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
new file mode 100644
index 0000000..aea4359
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -0,0 +1,226 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/qe_io.c
+ *
+ * QE Parallel I/O ports configuration routines
+ *
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Li Yang <LeoLi@freescale.com>
+ * Based on code from Shlomi Gridish <gridish@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+
+#undef DEBUG
+
+#define NUM_OF_PINS	32
+
+struct port_regs {
+	__be32	cpodr;		/* Open drain register */
+	__be32	cpdata;		/* Data register */
+	__be32	cpdir1;		/* Direction register */
+	__be32	cpdir2;		/* Direction register */
+	__be32	cppar1;		/* Pin assignment register */
+	__be32	cppar2;		/* Pin assignment register */
+};
+
+static struct port_regs *par_io = NULL;
+static int num_par_io_ports = 0;
+
+int par_io_init(struct device_node *np)
+{
+	struct resource res;
+	int ret;
+	const u32 *num_ports;
+
+	/* Map Parallel I/O ports registers */
+	ret = of_address_to_resource(np, 0, &res);
+	if (ret)
+		return ret;
+	par_io = ioremap(res.start, res.end - res.start + 1);
+
+	num_ports = get_property(np, "num-ports", NULL);
+	if (num_ports)
+		num_par_io_ports = *num_ports;
+
+	return 0;
+}
+
+int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
+		      int assignment, int has_irq)
+{
+	u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val;
+
+	if (!par_io)
+		return -1;
+
+	/* calculate pin location for single and 2 bits information */
+	pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
+
+	/* Set open drain, if required */
+	tmp_val = in_be32(&par_io[port].cpodr);
+	if (open_drain)
+		out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val);
+	else
+		out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val);
+
+	/* define direction */
+	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+		in_be32(&par_io[port].cpdir2) :
+		in_be32(&par_io[port].cpdir1);
+
+	/* get all bits mask for 2 bit per port */
+	pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS -
+				(pin % (NUM_OF_PINS / 2) + 1) * 2));
+
+	/* Get the final mask we need for the right definition */
+	new_mask2bits = (u32) (dir << (NUM_OF_PINS -
+				(pin % (NUM_OF_PINS / 2) + 1) * 2));
+
+	/* clear and set 2 bits mask */
+	if (pin > (NUM_OF_PINS / 2) - 1) {
+		out_be32(&par_io[port].cpdir2,
+			 ~pin_mask2bits & tmp_val);
+		tmp_val &= ~pin_mask2bits;
+		out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val);
+	} else {
+		out_be32(&par_io[port].cpdir1,
+			 ~pin_mask2bits & tmp_val);
+		tmp_val &= ~pin_mask2bits;
+		out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val);
+	}
+	/* define pin assignment */
+	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+		in_be32(&par_io[port].cppar2) :
+		in_be32(&par_io[port].cppar1);
+
+	new_mask2bits = (u32) (assignment << (NUM_OF_PINS -
+			(pin % (NUM_OF_PINS / 2) + 1) * 2));
+	/* clear and set 2 bits mask */
+	if (pin > (NUM_OF_PINS / 2) - 1) {
+		out_be32(&par_io[port].cppar2,
+			 ~pin_mask2bits & tmp_val);
+		tmp_val &= ~pin_mask2bits;
+		out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val);
+	} else {
+		out_be32(&par_io[port].cppar1,
+			 ~pin_mask2bits & tmp_val);
+		tmp_val &= ~pin_mask2bits;
+		out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(par_io_config_pin);
+
+int par_io_data_set(u8 port, u8 pin, u8 val)
+{
+	u32 pin_mask, tmp_val;
+
+	if (port >= num_par_io_ports)
+		return -EINVAL;
+	if (pin >= NUM_OF_PINS)
+		return -EINVAL;
+	/* calculate pin location */
+	pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin));
+
+	tmp_val = in_be32(&par_io[port].cpdata);
+
+	if (val == 0)		/* clear */
+		out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val);
+	else			/* set */
+		out_be32(&par_io[port].cpdata, pin_mask | tmp_val);
+
+	return 0;
+}
+EXPORT_SYMBOL(par_io_data_set);
+
+int par_io_of_config(struct device_node *np)
+{
+	struct device_node *pio;
+	const phandle *ph;
+	int pio_map_len;
+	const unsigned int *pio_map;
+
+	if (par_io == NULL) {
+		printk(KERN_ERR "par_io not initialized \n");
+		return -1;
+	}
+
+	ph = get_property(np, "pio-handle", NULL);
+	if (ph == 0) {
+		printk(KERN_ERR "pio-handle not available \n");
+		return -1;
+	}
+
+	pio = of_find_node_by_phandle(*ph);
+
+	pio_map = get_property(pio, "pio-map", &pio_map_len);
+	if (pio_map == NULL) {
+		printk(KERN_ERR "pio-map is not set! \n");
+		return -1;
+	}
+	pio_map_len /= sizeof(unsigned int);
+	if ((pio_map_len % 6) != 0) {
+		printk(KERN_ERR "pio-map format wrong! \n");
+		return -1;
+	}
+
+	while (pio_map_len > 0) {
+		par_io_config_pin((u8) pio_map[0], (u8) pio_map[1],
+				(int) pio_map[2], (int) pio_map[3],
+				(int) pio_map[4], (int) pio_map[5]);
+		pio_map += 6;
+		pio_map_len -= 6;
+	}
+	of_node_put(pio);
+	return 0;
+}
+EXPORT_SYMBOL(par_io_of_config);
+
+#ifdef DEBUG
+static void dump_par_io(void)
+{
+	int i;
+
+	printk(KERN_INFO "PAR IO registars:\n");
+	printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io);
+	for (i = 0; i < num_par_io_ports; i++) {
+		printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n",
+		       i, (u32) & par_io[i].cpodr,
+		       in_be32(&par_io[i].cpodr));
+		printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n",
+		       i, (u32) & par_io[i].cpdata,
+		       in_be32(&par_io[i].cpdata));
+		printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n",
+		       i, (u32) & par_io[i].cpdir1,
+		       in_be32(&par_io[i].cpdir1));
+		printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n",
+		       i, (u32) & par_io[i].cpdir2,
+		       in_be32(&par_io[i].cpdir2));
+		printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n",
+		       i, (u32) & par_io[i].cppar1,
+		       in_be32(&par_io[i].cppar1));
+		printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n",
+		       i, (u32) & par_io[i].cppar2,
+		       in_be32(&par_io[i].cppar2));
+	}
+
+}
+EXPORT_SYMBOL(dump_par_io);
+#endif /* DEBUG */
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
new file mode 100644
index 0000000..916c9e5
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/ucc.c
@@ -0,0 +1,251 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/ucc.c
+ *
+ * QE UCC API Set - UCC specific routines implementations.
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+#include <asm/ucc.h>
+
+static DEFINE_SPINLOCK(ucc_lock);
+
+int ucc_set_qe_mux_mii_mng(int ucc_num)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ucc_lock, flags);
+	out_be32(&qe_immr->qmx.cmxgcr,
+		 ((in_be32(&qe_immr->qmx.cmxgcr) &
+		   ~QE_CMXGCR_MII_ENET_MNG) |
+		  (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT)));
+	spin_unlock_irqrestore(&ucc_lock, flags);
+
+	return 0;
+}
+
+int ucc_set_type(int ucc_num, struct ucc_common *regs,
+		 enum ucc_speed_type speed)
+{
+	u8 guemr = 0;
+
+	/* check if the UCC number is in range. */
+	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+		return -EINVAL;
+
+	guemr = regs->guemr;
+	guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX);
+	switch (speed) {
+	case UCC_SPEED_TYPE_SLOW:
+		guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX);
+		break;
+	case UCC_SPEED_TYPE_FAST:
+		guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX);
+		break;
+	default:
+		return -EINVAL;
+	}
+	regs->guemr = guemr;
+
+	return 0;
+}
+
+int ucc_init_guemr(struct ucc_common *regs)
+{
+	u8 guemr = 0;
+
+	if (!regs)
+		return -EINVAL;
+
+	/* Set bit 3 (which is reserved in the GUEMR register) to 1 */
+	guemr = UCC_GUEMR_SET_RESERVED3;
+
+	regs->guemr = guemr;
+
+	return 0;
+}
+
+static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num,
+			   u8 * shift)
+{
+	switch (ucc_num) {
+	case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
+		*reg_num = 1;
+		*shift = 16;
+		break;
+	case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
+		*reg_num = 1;
+		*shift = 0;
+		break;
+	case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
+		*reg_num = 2;
+		*shift = 16;
+		break;
+	case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
+		*reg_num = 2;
+		*shift = 0;
+		break;
+	case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
+		*reg_num = 3;
+		*shift = 16;
+		break;
+	case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
+		*reg_num = 3;
+		*shift = 0;
+		break;
+	case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
+		*reg_num = 4;
+		*shift = 16;
+		break;
+	case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
+		*reg_num = 4;
+		*shift = 0;
+		break;
+	default:
+		break;
+	}
+}
+
+int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask)
+{
+	volatile u32 *p_cmxucr;
+	u8 reg_num;
+	u8 shift;
+
+	/* check if the UCC number is in range. */
+	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+		return -EINVAL;
+
+	get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
+
+	if (set)
+		out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift));
+	else
+		out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift));
+
+	return 0;
+}
+
+int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode)
+{
+	volatile u32 *p_cmxucr;
+	u8 reg_num;
+	u8 shift;
+	u32 clock_bits;
+	u32 clock_mask;
+	int source = -1;
+
+	/* check if the UCC number is in range. */
+	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+		return -EINVAL;
+
+	if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) {
+		printk(KERN_ERR
+		       "ucc_set_qe_mux_rxtx: bad comm mode type passed.");
+		return -EINVAL;
+	}
+
+	get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
+
+	switch (reg_num) {
+	case 1:
+		switch (clock) {
+		case QE_BRG1:	source = 1; break;
+		case QE_BRG2:	source = 2; break;
+		case QE_BRG7:	source = 3; break;
+		case QE_BRG8:	source = 4; break;
+		case QE_CLK9:	source = 5; break;
+		case QE_CLK10:	source = 6; break;
+		case QE_CLK11:	source = 7; break;
+		case QE_CLK12:	source = 8; break;
+		case QE_CLK15:	source = 9; break;
+		case QE_CLK16:	source = 10; break;
+		default: 	source = -1; break;
+		}
+		break;
+	case 2:
+		switch (clock) {
+		case QE_BRG5:	source = 1; break;
+		case QE_BRG6:	source = 2; break;
+		case QE_BRG7:	source = 3; break;
+		case QE_BRG8:	source = 4; break;
+		case QE_CLK13:	source = 5; break;
+		case QE_CLK14:	source = 6; break;
+		case QE_CLK19:	source = 7; break;
+		case QE_CLK20:	source = 8; break;
+		case QE_CLK15:	source = 9; break;
+		case QE_CLK16:	source = 10; break;
+		default: 	source = -1; break;
+		}
+		break;
+	case 3:
+		switch (clock) {
+		case QE_BRG9:	source = 1; break;
+		case QE_BRG10:	source = 2; break;
+		case QE_BRG15:	source = 3; break;
+		case QE_BRG16:	source = 4; break;
+		case QE_CLK3:	source = 5; break;
+		case QE_CLK4:	source = 6; break;
+		case QE_CLK17:	source = 7; break;
+		case QE_CLK18:	source = 8; break;
+		case QE_CLK7:	source = 9; break;
+		case QE_CLK8:	source = 10; break;
+		default:	source = -1; break;
+		}
+		break;
+	case 4:
+		switch (clock) {
+		case QE_BRG13:	source = 1; break;
+		case QE_BRG14:	source = 2; break;
+		case QE_BRG15:	source = 3; break;
+		case QE_BRG16:	source = 4; break;
+		case QE_CLK5:	source = 5; break;
+		case QE_CLK6:	source = 6; break;
+		case QE_CLK21:	source = 7; break;
+		case QE_CLK22:	source = 8; break;
+		case QE_CLK7:	source = 9; break;
+		case QE_CLK8:	source = 10; break;
+		default: 	source = -1; break;
+		}
+		break;
+	default:
+		source = -1;
+		break;
+	}
+
+	if (source == -1) {
+		printk(KERN_ERR
+		     "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC.");
+		return -ENOENT;
+	}
+
+	clock_bits = (u32) source;
+	clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK;
+	if (mode == COMM_DIR_RX) {
+		clock_bits <<= 4;  /* Rx field is 4 bits to left of Tx field */
+		clock_mask <<= 4;  /* Rx field is 4 bits to left of Tx field */
+	}
+	clock_bits <<= shift;
+	clock_mask <<= shift;
+
+	out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits);
+
+	return 0;
+}
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
new file mode 100644
index 0000000..c2be734
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -0,0 +1,396 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/ucc_fast.c
+ *
+ * QE UCC Fast API Set - UCC Fast specific routines implementations.
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include <asm/ucc.h>
+#include <asm/ucc_fast.h>
+
+#define uccf_printk(level, format, arg...) \
+	printk(level format "\n", ## arg)
+
+#define uccf_dbg(format, arg...) \
+	uccf_printk(KERN_DEBUG , format , ## arg)
+#define uccf_err(format, arg...) \
+	uccf_printk(KERN_ERR , format , ## arg)
+#define uccf_info(format, arg...) \
+	uccf_printk(KERN_INFO , format , ## arg)
+#define uccf_warn(format, arg...) \
+	uccf_printk(KERN_WARNING , format , ## arg)
+
+#ifdef UCCF_VERBOSE_DEBUG
+#define uccf_vdbg uccf_dbg
+#else
+#define uccf_vdbg(fmt, args...) do { } while (0)
+#endif				/* UCCF_VERBOSE_DEBUG */
+
+void ucc_fast_dump_regs(struct ucc_fast_private * uccf)
+{
+	uccf_info("UCC%d Fast registers:", uccf->uf_info->ucc_num);
+	uccf_info("Base address: 0x%08x", (u32) uccf->uf_regs);
+
+	uccf_info("gumr  : addr - 0x%08x, val - 0x%08x",
+		  (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr));
+	uccf_info("upsmr : addr - 0x%08x, val - 0x%08x",
+		  (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr));
+	uccf_info("utodr : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr));
+	uccf_info("udsr  : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr));
+	uccf_info("ucce  : addr - 0x%08x, val - 0x%08x",
+		  (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce));
+	uccf_info("uccm  : addr - 0x%08x, val - 0x%08x",
+		  (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm));
+	uccf_info("uccs  : addr - 0x%08x, val - 0x%02x",
+		  (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs);
+	uccf_info("urfb  : addr - 0x%08x, val - 0x%08x",
+		  (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb));
+	uccf_info("urfs  : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs));
+	uccf_info("urfet : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet));
+	uccf_info("urfset: addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->urfset,
+		  in_be16(&uccf->uf_regs->urfset));
+	uccf_info("utfb  : addr - 0x%08x, val - 0x%08x",
+		  (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb));
+	uccf_info("utfs  : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs));
+	uccf_info("utfet : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet));
+	uccf_info("utftt : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt));
+	uccf_info("utpt  : addr - 0x%08x, val - 0x%04x",
+		  (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt));
+	uccf_info("urtry : addr - 0x%08x, val - 0x%08x",
+		  (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry));
+	uccf_info("guemr : addr - 0x%08x, val - 0x%02x",
+		  (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr);
+}
+
+u32 ucc_fast_get_qe_cr_subblock(int uccf_num)
+{
+	switch (uccf_num) {
+	case 0:	return QE_CR_SUBBLOCK_UCCFAST1;
+	case 1: return QE_CR_SUBBLOCK_UCCFAST2;
+	case 2: return QE_CR_SUBBLOCK_UCCFAST3;
+	case 3: return QE_CR_SUBBLOCK_UCCFAST4;
+	case 4: return QE_CR_SUBBLOCK_UCCFAST5;
+	case 5: return QE_CR_SUBBLOCK_UCCFAST6;
+	case 6: return QE_CR_SUBBLOCK_UCCFAST7;
+	case 7:	return QE_CR_SUBBLOCK_UCCFAST8;
+	default: return QE_CR_SUBBLOCK_INVALID;
+	}
+}
+
+void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf)
+{
+	out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
+}
+
+void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode)
+{
+	struct ucc_fast *uf_regs;
+	u32 gumr;
+
+	uf_regs = uccf->uf_regs;
+
+	/* Enable reception and/or transmission on this UCC. */
+	gumr = in_be32(&uf_regs->gumr);
+	if (mode & COMM_DIR_TX) {
+		gumr |= UCC_FAST_GUMR_ENT;
+		uccf->enabled_tx = 1;
+	}
+	if (mode & COMM_DIR_RX) {
+		gumr |= UCC_FAST_GUMR_ENR;
+		uccf->enabled_rx = 1;
+	}
+	out_be32(&uf_regs->gumr, gumr);
+}
+
+void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode)
+{
+	struct ucc_fast *uf_regs;
+	u32 gumr;
+
+	uf_regs = uccf->uf_regs;
+
+	/* Disable reception and/or transmission on this UCC. */
+	gumr = in_be32(&uf_regs->gumr);
+	if (mode & COMM_DIR_TX) {
+		gumr &= ~UCC_FAST_GUMR_ENT;
+		uccf->enabled_tx = 0;
+	}
+	if (mode & COMM_DIR_RX) {
+		gumr &= ~UCC_FAST_GUMR_ENR;
+		uccf->enabled_rx = 0;
+	}
+	out_be32(&uf_regs->gumr, gumr);
+}
+
+int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret)
+{
+	struct ucc_fast_private *uccf;
+	struct ucc_fast *uf_regs;
+	u32 gumr = 0;
+	int ret;
+
+	uccf_vdbg("%s: IN", __FUNCTION__);
+
+	if (!uf_info)
+		return -EINVAL;
+
+	/* check if the UCC port number is in range. */
+	if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
+		uccf_err("ucc_fast_init: Illagal UCC number!");
+		return -EINVAL;
+	}
+
+	/* Check that 'max_rx_buf_length' is properly aligned (4). */
+	if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) {
+		uccf_err("ucc_fast_init: max_rx_buf_length not aligned.");
+		return -EINVAL;
+	}
+
+	/* Validate Virtual Fifo register values */
+	if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) {
+		uccf_err
+		    ("ucc_fast_init: Virtual Fifo register urfs too small.");
+		return -EINVAL;
+	}
+
+	if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+		uccf_err
+		    ("ucc_fast_init: Virtual Fifo register urfs not aligned.");
+		return -EINVAL;
+	}
+
+	if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+		uccf_err
+		    ("ucc_fast_init: Virtual Fifo register urfet not aligned.");
+		return -EINVAL;
+	}
+
+	if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+		uccf_err
+		   ("ucc_fast_init: Virtual Fifo register urfset not aligned.");
+		return -EINVAL;
+	}
+
+	if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+		uccf_err
+		    ("ucc_fast_init: Virtual Fifo register utfs not aligned.");
+		return -EINVAL;
+	}
+
+	if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+		uccf_err
+		    ("ucc_fast_init: Virtual Fifo register utfet not aligned.");
+		return -EINVAL;
+	}
+
+	if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+		uccf_err
+		    ("ucc_fast_init: Virtual Fifo register utftt not aligned.");
+		return -EINVAL;
+	}
+
+	uccf = (struct ucc_fast_private *)
+		 kmalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
+	if (!uccf) {
+		uccf_err
+		    ("ucc_fast_init: No memory for UCC slow data structure!");
+		return -ENOMEM;
+	}
+	memset(uccf, 0, sizeof(struct ucc_fast_private));
+
+	/* Fill fast UCC structure */
+	uccf->uf_info = uf_info;
+	/* Set the PHY base address */
+	uccf->uf_regs =
+	    (struct ucc_fast *) ioremap(uf_info->regs, sizeof(struct ucc_fast));
+	if (uccf->uf_regs == NULL) {
+		uccf_err
+		    ("ucc_fast_init: No memory map for UCC slow controller!");
+		return -ENOMEM;
+	}
+
+	uccf->enabled_tx = 0;
+	uccf->enabled_rx = 0;
+	uccf->stopped_tx = 0;
+	uccf->stopped_rx = 0;
+	uf_regs = uccf->uf_regs;
+	uccf->p_ucce = (u32 *) & (uf_regs->ucce);
+	uccf->p_uccm = (u32 *) & (uf_regs->uccm);
+#ifdef STATISTICS
+	uccf->tx_frames = 0;
+	uccf->rx_frames = 0;
+	uccf->rx_discarded = 0;
+#endif				/* STATISTICS */
+
+	/* Init Guemr register */
+	if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) {
+		uccf_err("ucc_fast_init: Could not init the guemr register.");
+		ucc_fast_free(uccf);
+		return ret;
+	}
+
+	/* Set UCC to fast type */
+	if ((ret = ucc_set_type(uf_info->ucc_num,
+				(struct ucc_common *) (uf_regs),
+				UCC_SPEED_TYPE_FAST))) {
+		uccf_err("ucc_fast_init: Could not set type to fast.");
+		ucc_fast_free(uccf);
+		return ret;
+	}
+
+	uccf->mrblr = uf_info->max_rx_buf_length;
+
+	/* Set GUMR */
+	/* For more details see the hardware spec. */
+	/* gumr starts as zero. */
+	if (uf_info->tci)
+		gumr |= UCC_FAST_GUMR_TCI;
+	gumr |= uf_info->ttx_trx;
+	if (uf_info->cdp)
+		gumr |= UCC_FAST_GUMR_CDP;
+	if (uf_info->ctsp)
+		gumr |= UCC_FAST_GUMR_CTSP;
+	if (uf_info->cds)
+		gumr |= UCC_FAST_GUMR_CDS;
+	if (uf_info->ctss)
+		gumr |= UCC_FAST_GUMR_CTSS;
+	if (uf_info->txsy)
+		gumr |= UCC_FAST_GUMR_TXSY;
+	if (uf_info->rsyn)
+		gumr |= UCC_FAST_GUMR_RSYN;
+	gumr |= uf_info->synl;
+	if (uf_info->rtsm)
+		gumr |= UCC_FAST_GUMR_RTSM;
+	gumr |= uf_info->renc;
+	if (uf_info->revd)
+		gumr |= UCC_FAST_GUMR_REVD;
+	gumr |= uf_info->tenc;
+	gumr |= uf_info->tcrc;
+	gumr |= uf_info->mode;
+	out_be32(&uf_regs->gumr, gumr);
+
+	/* Allocate memory for Tx Virtual Fifo */
+	uccf->ucc_fast_tx_virtual_fifo_base_offset =
+	    qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+	if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
+		uccf_err
+		    ("ucc_fast_init: Can not allocate MURAM memory for "
+			"struct ucc_fastx_virtual_fifo_base_offset.");
+		uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
+		ucc_fast_free(uccf);
+		return -ENOMEM;
+	}
+
+	/* Allocate memory for Rx Virtual Fifo */
+	uccf->ucc_fast_rx_virtual_fifo_base_offset =
+	    qe_muram_alloc(uf_info->urfs +
+			   (u32)
+			   UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
+			   UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+	if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
+		uccf_err
+		    ("ucc_fast_init: Can not allocate MURAM memory for "
+			"ucc_fast_rx_virtual_fifo_base_offset.");
+		uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
+		ucc_fast_free(uccf);
+		return -ENOMEM;
+	}
+
+	/* Set Virtual Fifo registers */
+	out_be16(&uf_regs->urfs, uf_info->urfs);
+	out_be16(&uf_regs->urfet, uf_info->urfet);
+	out_be16(&uf_regs->urfset, uf_info->urfset);
+	out_be16(&uf_regs->utfs, uf_info->utfs);
+	out_be16(&uf_regs->utfet, uf_info->utfet);
+	out_be16(&uf_regs->utftt, uf_info->utftt);
+	/* utfb, urfb are offsets from MURAM base */
+	out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset);
+	out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset);
+
+	/* Mux clocking */
+	/* Grant Support */
+	ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support);
+	/* Breakpoint Support */
+	ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support);
+	/* Set Tsa or NMSI mode. */
+	ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa);
+	/* If NMSI (not Tsa), set Tx and Rx clock. */
+	if (!uf_info->tsa) {
+		/* Rx clock routing */
+		if (uf_info->rx_clock != QE_CLK_NONE) {
+			if (ucc_set_qe_mux_rxtx
+			    (uf_info->ucc_num, uf_info->rx_clock,
+			     COMM_DIR_RX)) {
+				uccf_err
+		("ucc_fast_init: Illegal value for parameter 'RxClock'.");
+				ucc_fast_free(uccf);
+				return -EINVAL;
+			}
+		}
+		/* Tx clock routing */
+		if (uf_info->tx_clock != QE_CLK_NONE) {
+			if (ucc_set_qe_mux_rxtx
+			    (uf_info->ucc_num, uf_info->tx_clock,
+			     COMM_DIR_TX)) {
+				uccf_err
+		("ucc_fast_init: Illegal value for parameter 'TxClock'.");
+				ucc_fast_free(uccf);
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* Set interrupt mask register at UCC level. */
+	out_be32(&uf_regs->uccm, uf_info->uccm_mask);
+
+	/* First, clear anything pending at UCC level,
+	 * otherwise, old garbage may come through
+	 * as soon as the dam is opened
+	 * Writing '1' clears
+	 */
+	out_be32(&uf_regs->ucce, 0xffffffff);
+
+	*uccf_ret = uccf;
+	return 0;
+}
+
+void ucc_fast_free(struct ucc_fast_private * uccf)
+{
+	if (!uccf)
+		return;
+
+	if (uccf->ucc_fast_tx_virtual_fifo_base_offset)
+		qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset);
+
+	if (uccf->ucc_fast_rx_virtual_fifo_base_offset)
+		qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset);
+
+	kfree(uccf);
+}
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
new file mode 100644
index 0000000..1fb88ef
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * QE UCC Slow API Set - UCC Slow specific routines implementations.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include <asm/ucc.h>
+#include <asm/ucc_slow.h>
+
+#define uccs_printk(level, format, arg...) \
+        printk(level format "\n", ## arg)
+
+#define uccs_dbg(format, arg...) \
+	uccs_printk(KERN_DEBUG , format , ## arg)
+#define uccs_err(format, arg...) \
+	uccs_printk(KERN_ERR , format , ## arg)
+#define uccs_info(format, arg...) \
+	uccs_printk(KERN_INFO , format , ## arg)
+#define uccs_warn(format, arg...) \
+	uccs_printk(KERN_WARNING , format , ## arg)
+
+#ifdef UCCS_VERBOSE_DEBUG
+#define uccs_vdbg uccs_dbg
+#else
+#define uccs_vdbg(fmt, args...) do { } while (0)
+#endif				/* UCCS_VERBOSE_DEBUG */
+
+u32 ucc_slow_get_qe_cr_subblock(int uccs_num)
+{
+	switch (uccs_num) {
+	case 0: return QE_CR_SUBBLOCK_UCCSLOW1;
+	case 1: return QE_CR_SUBBLOCK_UCCSLOW2;
+	case 2: return QE_CR_SUBBLOCK_UCCSLOW3;
+	case 3: return QE_CR_SUBBLOCK_UCCSLOW4;
+	case 4: return QE_CR_SUBBLOCK_UCCSLOW5;
+	case 5: return QE_CR_SUBBLOCK_UCCSLOW6;
+	case 6: return QE_CR_SUBBLOCK_UCCSLOW7;
+	case 7: return QE_CR_SUBBLOCK_UCCSLOW8;
+	default: return QE_CR_SUBBLOCK_INVALID;
+	}
+}
+
+void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs)
+{
+	out_be16(&uccs->us_regs->utodr, UCC_SLOW_TOD);
+}
+
+void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs)
+{
+	struct ucc_slow_info *us_info = uccs->us_info;
+	u32 id;
+
+	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+	qe_issue_cmd(QE_GRACEFUL_STOP_TX, id,
+			 QE_CR_PROTOCOL_UNSPECIFIED, 0);
+}
+
+void ucc_slow_stop_tx(struct ucc_slow_private * uccs)
+{
+	struct ucc_slow_info *us_info = uccs->us_info;
+	u32 id;
+
+	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+	qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
+}
+
+void ucc_slow_restart_tx(struct ucc_slow_private * uccs)
+{
+	struct ucc_slow_info *us_info = uccs->us_info;
+	u32 id;
+
+	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+	qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
+}
+
+void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode)
+{
+	struct ucc_slow *us_regs;
+	u32 gumr_l;
+
+	us_regs = uccs->us_regs;
+
+	/* Enable reception and/or transmission on this UCC. */
+	gumr_l = in_be32(&us_regs->gumr_l);
+	if (mode & COMM_DIR_TX) {
+		gumr_l |= UCC_SLOW_GUMR_L_ENT;
+		uccs->enabled_tx = 1;
+	}
+	if (mode & COMM_DIR_RX) {
+		gumr_l |= UCC_SLOW_GUMR_L_ENR;
+		uccs->enabled_rx = 1;
+	}
+	out_be32(&us_regs->gumr_l, gumr_l);
+}
+
+void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode)
+{
+	struct ucc_slow *us_regs;
+	u32 gumr_l;
+
+	us_regs = uccs->us_regs;
+
+	/* Disable reception and/or transmission on this UCC. */
+	gumr_l = in_be32(&us_regs->gumr_l);
+	if (mode & COMM_DIR_TX) {
+		gumr_l &= ~UCC_SLOW_GUMR_L_ENT;
+		uccs->enabled_tx = 0;
+	}
+	if (mode & COMM_DIR_RX) {
+		gumr_l &= ~UCC_SLOW_GUMR_L_ENR;
+		uccs->enabled_rx = 0;
+	}
+	out_be32(&us_regs->gumr_l, gumr_l);
+}
+
+int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret)
+{
+	u32 i;
+	struct ucc_slow *us_regs;
+	u32 gumr;
+	u8 function_code = 0;
+	u8 *bd;
+	struct ucc_slow_private *uccs;
+	u32 id;
+	u32 command;
+	int ret;
+
+	uccs_vdbg("%s: IN", __FUNCTION__);
+
+	if (!us_info)
+		return -EINVAL;
+
+	/* check if the UCC port number is in range. */
+	if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) {
+		uccs_err("ucc_slow_init: Illagal UCC number!");
+		return -EINVAL;
+	}
+
+	/*
+	 * Set mrblr
+	 * Check that 'max_rx_buf_length' is properly aligned (4), unless
+ 	 * rfw is 1, meaning that QE accepts one byte at a time, unlike normal
+	 * case when QE accepts 32 bits at a time.
+	 */
+	if ((!us_info->rfw) &&
+		(us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) {
+		uccs_err("max_rx_buf_length not aligned.");
+		return -EINVAL;
+	}
+
+	uccs = (struct ucc_slow_private *)
+		kmalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
+	if (!uccs) {
+		uccs_err
+		    ("ucc_slow_init: No memory for UCC slow data structure!");
+		return -ENOMEM;
+	}
+	memset(uccs, 0, sizeof(struct ucc_slow_private));
+
+	/* Fill slow UCC structure */
+	uccs->us_info = us_info;
+	uccs->saved_uccm = 0;
+	uccs->p_rx_frame = 0;
+	uccs->us_regs = us_info->us_regs;
+	us_regs = uccs->us_regs;
+	uccs->p_ucce = (u16 *) & (us_regs->ucce);
+	uccs->p_uccm = (u16 *) & (us_regs->uccm);
+#ifdef STATISTICS
+	uccs->rx_frames = 0;
+	uccs->tx_frames = 0;
+	uccs->rx_discarded = 0;
+#endif				/* STATISTICS */
+
+	/* Get PRAM base */
+	uccs->us_pram_offset = qe_muram_alloc(UCC_SLOW_PRAM_SIZE,
+						 ALIGNMENT_OF_UCC_SLOW_PRAM);
+	if (IS_MURAM_ERR(uccs->us_pram_offset)) {
+		uccs_err
+		    ("ucc_slow_init: Can not allocate MURAM memory "
+			"for Slow UCC.");
+		ucc_slow_free(uccs);
+		return -ENOMEM;
+	}
+	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+	qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED,
+			(u32) uccs->us_pram_offset);
+
+	uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
+
+	/* Init Guemr register */
+	if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->us_regs)))) {
+		uccs_err("ucc_slow_init: Could not init the guemr register.");
+		ucc_slow_free(uccs);
+		return ret;
+	}
+
+	/* Set UCC to slow type */
+	if ((ret = ucc_set_type(us_info->ucc_num,
+				(struct ucc_common *) (us_info->us_regs),
+				UCC_SPEED_TYPE_SLOW))) {
+		uccs_err("ucc_slow_init: Could not init the guemr register.");
+		ucc_slow_free(uccs);
+		return ret;
+	}
+
+	out_be16(&uccs->us_pram->mrblr, us_info->max_rx_buf_length);
+
+	INIT_LIST_HEAD(&uccs->confQ);
+
+	/* Allocate BDs. */
+	uccs->rx_base_offset =
+		qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd),
+				QE_ALIGNMENT_OF_BD);
+	if (IS_MURAM_ERR(uccs->rx_base_offset)) {
+		uccs_err("ucc_slow_init: No memory for Rx BD's.");
+		uccs->rx_base_offset = 0;
+		ucc_slow_free(uccs);
+		return -ENOMEM;
+	}
+
+	uccs->tx_base_offset =
+		qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd),
+			QE_ALIGNMENT_OF_BD);
+	if (IS_MURAM_ERR(uccs->tx_base_offset)) {
+		uccs_err("ucc_slow_init: No memory for Tx BD's.");
+		uccs->tx_base_offset = 0;
+		ucc_slow_free(uccs);
+		return -ENOMEM;
+	}
+
+	/* Init Tx bds */
+	bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset);
+	for (i = 0; i < us_info->tx_bd_ring_len; i++) {
+		/* clear bd buffer */
+		out_be32(&(((struct qe_bd *)bd)->buf), 0);
+		/* set bd status and length */
+		out_be32((u32*)bd, 0);
+		bd += sizeof(struct qe_bd);
+	}
+	bd -= sizeof(struct qe_bd);
+	/* set bd status and length */
+	out_be32((u32*)bd, T_W);	/* for last BD set Wrap bit */
+
+	/* Init Rx bds */
+	bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset);
+	for (i = 0; i < us_info->rx_bd_ring_len; i++) {
+		/* set bd status and length */
+		out_be32((u32*)bd, 0);
+		/* clear bd buffer */
+		out_be32(&(((struct qe_bd *)bd)->buf), 0);
+		bd += sizeof(struct qe_bd);
+	}
+	bd -= sizeof(struct qe_bd);
+	/* set bd status and length */
+	out_be32((u32*)bd, R_W);	/* for last BD set Wrap bit */
+
+	/* Set GUMR (For more details see the hardware spec.). */
+	/* gumr_h */
+	gumr = 0;
+	gumr |= us_info->tcrc;
+	if (us_info->cdp)
+		gumr |= UCC_SLOW_GUMR_H_CDP;
+	if (us_info->ctsp)
+		gumr |= UCC_SLOW_GUMR_H_CTSP;
+	if (us_info->cds)
+		gumr |= UCC_SLOW_GUMR_H_CDS;
+	if (us_info->ctss)
+		gumr |= UCC_SLOW_GUMR_H_CTSS;
+	if (us_info->tfl)
+		gumr |= UCC_SLOW_GUMR_H_TFL;
+	if (us_info->rfw)
+		gumr |= UCC_SLOW_GUMR_H_RFW;
+	if (us_info->txsy)
+		gumr |= UCC_SLOW_GUMR_H_TXSY;
+	if (us_info->rtsm)
+		gumr |= UCC_SLOW_GUMR_H_RTSM;
+	out_be32(&us_regs->gumr_h, gumr);
+
+	/* gumr_l */
+	gumr = 0;
+	if (us_info->tci)
+		gumr |= UCC_SLOW_GUMR_L_TCI;
+	if (us_info->rinv)
+		gumr |= UCC_SLOW_GUMR_L_RINV;
+	if (us_info->tinv)
+		gumr |= UCC_SLOW_GUMR_L_TINV;
+	if (us_info->tend)
+		gumr |= UCC_SLOW_GUMR_L_TEND;
+	gumr |= us_info->tdcr;
+	gumr |= us_info->rdcr;
+	gumr |= us_info->tenc;
+	gumr |= us_info->renc;
+	gumr |= us_info->diag;
+	gumr |= us_info->mode;
+	out_be32(&us_regs->gumr_l, gumr);
+
+	/* Function code registers */
+	/* function_code has initial value 0 */
+
+	/* if the data is in cachable memory, the 'global' */
+	/* in the function code should be set. */
+	function_code |= us_info->data_mem_part;
+	function_code |= QE_BMR_BYTE_ORDER_BO_MOT;	/* Required for QE */
+	uccs->us_pram->tfcr = function_code;
+	uccs->us_pram->rfcr = function_code;
+
+	/* rbase, tbase are offsets from MURAM base */
+	out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset);
+	out_be16(&uccs->us_pram->tbase, uccs->us_pram_offset);
+
+	/* Mux clocking */
+	/* Grant Support */
+	ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support);
+	/* Breakpoint Support */
+	ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support);
+	/* Set Tsa or NMSI mode. */
+	ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa);
+	/* If NMSI (not Tsa), set Tx and Rx clock. */
+	if (!us_info->tsa) {
+		/* Rx clock routing */
+		if (ucc_set_qe_mux_rxtx
+		    (us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) {
+			uccs_err
+			    ("ucc_slow_init: Illegal value for parameter"
+				" 'RxClock'.");
+			ucc_slow_free(uccs);
+			return -EINVAL;
+		}
+		/* Tx clock routing */
+		if (ucc_set_qe_mux_rxtx(us_info->ucc_num,
+				 us_info->tx_clock, COMM_DIR_TX)) {
+			uccs_err
+			    ("ucc_slow_init: Illegal value for parameter "
+				"'TxClock'.");
+			ucc_slow_free(uccs);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * INTERRUPTS
+	 */
+	/* Set interrupt mask register at UCC level. */
+	out_be16(&us_regs->uccm, us_info->uccm_mask);
+
+	/* First, clear anything pending at UCC level, */
+	/* otherwise, old garbage may come through */
+	/* as soon as the dam is opened. */
+
+	/* Writing '1' clears */
+	out_be16(&us_regs->ucce, 0xffff);
+
+	/* Issue QE Init command */
+	if (us_info->init_tx && us_info->init_rx)
+		command = QE_INIT_TX_RX;
+	else if (us_info->init_tx)
+		command = QE_INIT_TX;
+	else
+		command = QE_INIT_RX;	/* We know at least one is TRUE */
+	id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+	qe_issue_cmd(command, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+	*uccs_ret = uccs;
+	return 0;
+}
+
+void ucc_slow_free(struct ucc_slow_private * uccs)
+{
+	if (!uccs)
+		return;
+
+	if (uccs->rx_base_offset)
+		qe_muram_free(uccs->rx_base_offset);
+
+	if (uccs->tx_base_offset)
+		qe_muram_free(uccs->tx_base_offset);
+
+	if (uccs->us_pram) {
+		qe_muram_free(uccs->us_pram_offset);
+		uccs->us_pram = NULL;
+	}
+
+	kfree(uccs);
+}
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index f303846..11de090 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -9,7 +9,6 @@
  * option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/stddef.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 8adad14..708236f 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -2,6 +2,8 @@
  * Routines providing a simple monitor for use on the PowerMac.
  *
  * Copyright (C) 1996-2005 Paul Mackerras.
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -503,7 +505,7 @@
 
 	mtmsr(msr);		/* restore interrupt enable */
 
-	return cmd != 'X';
+	return cmd != 'X' && cmd != EOF;
 }
 
 int xmon(struct pt_regs *excp)
@@ -2597,3 +2599,34 @@
 }
 __initcall(setup_xmon_sysrq);
 #endif /* CONFIG_MAGIC_SYSRQ */
+
+int __initdata xmon_early, xmon_off;
+
+static int __init early_parse_xmon(char *p)
+{
+	if (!p || strncmp(p, "early", 5) == 0) {
+		/* just "xmon" is equivalent to "xmon=early" */
+		xmon_init(1);
+		xmon_early = 1;
+	} else if (strncmp(p, "on", 2) == 0)
+		xmon_init(1);
+	else if (strncmp(p, "off", 3) == 0)
+		xmon_off = 1;
+	else if (strncmp(p, "nobt", 4) == 0)
+		xmon_no_auto_backtrace = 1;
+	else
+		return 1;
+
+	return 0;
+}
+early_param("xmon", early_parse_xmon);
+
+void __init xmon_setup(void)
+{
+#ifdef CONFIG_XMON_DEFAULT
+	if (!xmon_off)
+		xmon_init(1);
+#endif
+	if (xmon_early)
+		debugger(NULL);
+}
diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c
index 0073527..8c880c0 100644
--- a/arch/ppc/amiga/time.c
+++ b/arch/ppc/amiga/time.c
@@ -1,4 +1,3 @@
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff --git a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h
index f5a5c0c..a6c0a13 100644
--- a/arch/ppc/platforms/4xx/cpci405.h
+++ b/arch/ppc/platforms/4xx/cpci405.h
@@ -13,7 +13,6 @@
 #ifndef __CPCI405_H__
 #define __CPCI405_H__
 
-#include <linux/config.h>
 #include <platforms/4xx/ibm405gp.h>
 #include <asm/ppcboot.h>
 
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index 4d9ff5c..67914fe 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -20,7 +20,6 @@
  * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com>
  */
 
-#include <linux/config.h>
 #include <linux/kprobes.h>
 #include <linux/ptrace.h>
 #include <linux/preempt.h>
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index d33f8a0..54d51b4 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -25,7 +25,6 @@
  * <zaitcev> Sounds reasonable
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 97bf87e8..74bef2a 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 718350a..826118ee 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -5,7 +5,6 @@
  * Refactoring for unified NCR/PCIO support 2002 Eric Brower (ebrower@usa.net)
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 238bbf6..7f92045 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 5cc5ab6..e21cd6a 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -15,7 +15,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/string.h>
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index d247ef4..a0d148ea 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/module.h"
 #include "linux/init.h"
 #include "linux/slab.h"
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 300a54a..c1c5604 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -5,7 +5,6 @@
  * Licensed under the GPL.
  */
 
-#include "linux/config.h"
 #include "linux/kernel.h"
 #include "linux/netdevice.h"
 #include "linux/rtnetlink.h"
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index ccea2d7..788da54 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -1,4 +1,3 @@
-#include "linux/config.h"
 #include "linux/kernel.h"
 #include "linux/stddef.h"
 #include "linux/init.h"
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 6f13e7c..ed9c590 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/fs.h"
 #include "linux/tty.h"
 #include "linux/tty_driver.h"
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index e4bfcfe..7a4897e 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/posix_types.h"
 #include "linux/tty.h"
 #include "linux/tty_flip.h"
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index fda4a394..f0b0668 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -20,7 +20,6 @@
 #define MAJOR_NR UBD_MAJOR
 #define UBD_SHIFT 4
 
-#include "linux/config.h"
 #include "linux/module.h"
 #include "linux/blkdev.h"
 #include "linux/hdreg.h"
diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
index d86ee14..d0b6901 100644
--- a/arch/um/include/mconsole_kern.h
+++ b/arch/um/include/mconsole_kern.h
@@ -6,7 +6,6 @@
 #ifndef __MCONSOLE_KERN_H__
 #define __MCONSOLE_KERN_H__
 
-#include "linux/config.h"
 #include "linux/list.h"
 #include "mconsole.h"
 
diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h
index e7539a8..88e5e77 100644
--- a/arch/um/include/mode_kern.h
+++ b/arch/um/include/mode_kern.h
@@ -6,8 +6,6 @@
 #ifndef __MODE_KERN_H__
 #define __MODE_KERN_H__
 
-#include "linux/config.h"
-
 #ifdef CONFIG_MODE_TT
 #include "mode_kern_tt.h"
 #endif
diff --git a/arch/um/include/skas/mmu-skas.h b/arch/um/include/skas/mmu-skas.h
index d8869a6..b26986c 100644
--- a/arch/um/include/skas/mmu-skas.h
+++ b/arch/um/include/skas/mmu-skas.h
@@ -6,7 +6,6 @@
 #ifndef __SKAS_MMU_H
 #define __SKAS_MMU_H
 
-#include "linux/config.h"
 #include "mm_id.h"
 #include "asm/ldt.h"
 
diff --git a/arch/um/include/sysdep-ppc/ptrace.h b/arch/um/include/sysdep-ppc/ptrace.h
index 8a27353..df2397d 100644
--- a/arch/um/include/sysdep-ppc/ptrace.h
+++ b/arch/um/include/sysdep-ppc/ptrace.h
@@ -5,7 +5,6 @@
 #ifndef __SYS_PTRACE_PPC_H
 #define __SYS_PTRACE_PPC_H
 
-#include "linux/config.h"
 #include "linux/types.h"
 
 /* the following taken from <asm-ppc/ptrace.h> */
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
index 4567f1e..5126a99 100644
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -6,7 +6,6 @@
 #ifndef __ARCH_UM_UACCESS_H
 #define __ARCH_UM_UACCESS_H
 
-#include "linux/config.h"
 #include "choose-mode.h"
 
 #ifdef CONFIG_MODE_TT
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index 49ed5dd..8cde431 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/mm.h"
 #include "linux/module.h"
 #include "linux/sched.h"
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index ce7f233..eee97bb 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -5,7 +5,6 @@
  *	Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
  */
 
-#include "linux/config.h"
 #include "linux/kernel.h"
 #include "linux/module.h"
 #include "linux/smp.h"
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index f030e44..0e00cf9 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/module.h"
 #include "linux/string.h"
 #include "linux/smp_lock.h"
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 4aa9808..2a32e5e 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/stddef.h"
 #include "linux/sys.h"
 #include "linux/sched.h"
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 27bbf54..0d2cce6 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/mm.h"
 #include "asm/pgtable.h"
 #include "mem_user.h"
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 4cd2ff5..c17eddc 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/sched.h"
 #include "linux/list.h"
 #include "linux/spinlock.h"
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 6e84963..27eb29c 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,7 +6,6 @@
 
 #include "linux/stddef.h"
 #include "linux/sched.h"
-#include "linux/config.h"
 #include "linux/mm.h"
 #include "asm/page.h"
 #include "asm/pgtable.h"
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 511116a..759b070 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/percpu.h"
 #include "asm/pgalloc.h"
 #include "asm/tlb.h"
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index b331e97..239c980 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/sched.h"
 #include "linux/kernel.h"
 #include "linux/module.h"
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index c7b195c..b5f124a 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -8,7 +8,6 @@
 #include "linux/sched.h"
 #include "linux/mm.h"
 #include "linux/spinlock.h"
-#include "linux/config.h"
 #include "linux/init.h"
 #include "linux/ptrace.h"
 #include "asm/semaphore.h"
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
index 2650638..68e1bf6 100644
--- a/arch/um/kernel/tt/gdb_kern.c
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -4,7 +4,6 @@
  */
 
 #include "linux/init.h"
-#include "linux/config.h"
 #include "mconsole_kern.h"
 
 #ifdef CONFIG_MCONSOLE
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
index 84a23b1..4d1929d 100644
--- a/arch/um/kernel/tt/mem.c
+++ b/arch/um/kernel/tt/mem.c
@@ -4,7 +4,6 @@
  */
 
 #include "linux/stddef.h"
-#include "linux/config.h"
 #include "linux/mm.h"
 #include "asm/uaccess.h"
 #include "mem_user.h"
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 97d88e7..66f43c9 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/kernel.h"
 #include "linux/sched.h"
 #include "linux/notifier.h"
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 69971b7..e299ee5 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -4,7 +4,6 @@
  */
 
 #include "linux/stddef.h"
-#include "linux/config.h"
 #include "linux/sched.h"
 #include "linux/slab.h"
 #include "linux/types.h"
diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
index d5244f0..171b3e9 100644
--- a/arch/um/sys-i386/sysrq.c
+++ b/arch/um/sys-i386/sysrq.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/kernel.h"
 #include "linux/smp.h"
 #include "linux/sched.h"
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
index 71b97962..643dab5 100644
--- a/arch/um/sys-i386/tls.c
+++ b/arch/um/sys-i386/tls.c
@@ -3,7 +3,6 @@
  * Licensed under the GPL
  */
 
-#include "linux/config.h"
 #include "linux/kernel.h"
 #include "linux/sched.h"
 #include "linux/slab.h"
diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c
index f4d1a4d..cd06f47 100644
--- a/arch/v850/kernel/time.c
+++ b/arch/v850/kernel/time.c
@@ -10,7 +10,6 @@
  *		"A Kernel Model for Precision Timekeeping" by Dave Mills
  */
 
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
index 2aa565c..d6ff88f 100644
--- a/arch/x86_64/boot/video.S
+++ b/arch/x86_64/boot/video.S
@@ -11,8 +11,6 @@
  *
  */
 
-#include <linux/config.h> /* for CONFIG_VIDEO_* */
-
 /* Enable autodetection of SVGA adapters and modes. */
 #undef CONFIG_VIDEO_SVGA
 
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 2fd5a67..82ef182 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -6,7 +6,6 @@
  * of ugly preprocessor tricks. Talk about very very poor man's inheritance.
  */ 
 #include <linux/types.h>
-#include <linux/config.h> 
 #include <linux/stddef.h>
 #include <linux/rwsem.h>
 #include <linux/sched.h>
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 2dd51f3..0612a33 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -43,17 +43,10 @@
 	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
 	BI(x,c) BI(x,d) BI(x,e) BI(x,f)
 
-#define BUILD_15_IRQS(x) \
-	BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
-	BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
-	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
-	BI(x,c) BI(x,d) BI(x,e)
-
 /*
  * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
  * (these are usually mapped to vectors 0x20-0x2f)
  */
-BUILD_16_IRQS(0x0)
 
 /*
  * The IO-APIC gives us many more interrupt sources. Most of these 
@@ -65,17 +58,12 @@
  *
  * (these are usually mapped into the 0x30-0xff vector range)
  */
-		   BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+				      BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
 BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
 BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
-BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
-
-#ifdef CONFIG_PCI_MSI
-	BUILD_15_IRQS(0xe)
-#endif
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
 
 #undef BUILD_16_IRQS
-#undef BUILD_15_IRQS
 #undef BI
 
 
@@ -88,29 +76,15 @@
 	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
 	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
 
-#define IRQLIST_15(x) \
-	IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
-	IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
-	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
-	IRQ(x,c), IRQ(x,d), IRQ(x,e)
-
 void (*interrupt[NR_IRQS])(void) = {
-	IRQLIST_16(0x0),
-
-			 IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
+					  IRQLIST_16(0x2), IRQLIST_16(0x3),
 	IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
 	IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
-	IRQLIST_16(0xc), IRQLIST_16(0xd)
-
-#ifdef CONFIG_PCI_MSI
-	, IRQLIST_15(0xe)
-#endif
-
+	IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
 };
 
 #undef IRQ
 #undef IRQLIST_16
-#undef IRQLIST_14
 
 /*
  * This is the 'legacy' 8259A Programmable Interrupt Controller,
@@ -121,42 +95,15 @@
  * moves to arch independent land
  */
 
-DEFINE_SPINLOCK(i8259A_lock);
-
 static int i8259A_auto_eoi;
-
-static void end_8259A_irq (unsigned int irq)
-{
-	if (irq > 256) { 
-		char var;
-		printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current));
-
-		BUG(); 
-	}
-
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
-	    irq_desc[irq].action)
-		enable_8259A_irq(irq);
-}
-
-#define shutdown_8259A_irq	disable_8259A_irq
-
+DEFINE_SPINLOCK(i8259A_lock);
 static void mask_and_ack_8259A(unsigned int);
 
-static unsigned int startup_8259A_irq(unsigned int irq)
-{ 
-	enable_8259A_irq(irq);
-	return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type i8259A_irq_type = {
-	.typename = "XT-PIC",
-	.startup = startup_8259A_irq,
-	.shutdown = shutdown_8259A_irq,
-	.enable = enable_8259A_irq,
-	.disable = disable_8259A_irq,
-	.ack = mask_and_ack_8259A,
-	.end = end_8259A_irq,
+static struct irq_chip i8259A_chip = {
+	.name		= "XT-PIC",
+	.mask		= disable_8259A_irq,
+	.unmask		= enable_8259A_irq,
+	.mask_ack	= mask_and_ack_8259A,
 };
 
 /*
@@ -231,7 +178,7 @@
 {
 	disable_irq_nosync(irq);
 	io_apic_irqs &= ~(1<<irq);
-	irq_desc[irq].chip = &i8259A_irq_type;
+	set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq);
 	enable_irq(irq);
 }
 
@@ -367,9 +314,9 @@
 		 * in AEOI mode we just have to mask the interrupt
 		 * when acking.
 		 */
-		i8259A_irq_type.ack = disable_8259A_irq;
+		i8259A_chip.mask_ack = disable_8259A_irq;
 	else
-		i8259A_irq_type.ack = mask_and_ack_8259A;
+		i8259A_chip.mask_ack = mask_and_ack_8259A;
 
 	udelay(100);		/* wait for 8259A to initialize */
 
@@ -447,6 +394,26 @@
  */
 
 static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL};
+DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
+	[0 ... FIRST_EXTERNAL_VECTOR - 1] = -1,
+	[FIRST_EXTERNAL_VECTOR + 0] = 0,
+	[FIRST_EXTERNAL_VECTOR + 1] = 1,
+	[FIRST_EXTERNAL_VECTOR + 2] = 2,
+	[FIRST_EXTERNAL_VECTOR + 3] = 3,
+	[FIRST_EXTERNAL_VECTOR + 4] = 4,
+	[FIRST_EXTERNAL_VECTOR + 5] = 5,
+	[FIRST_EXTERNAL_VECTOR + 6] = 6,
+	[FIRST_EXTERNAL_VECTOR + 7] = 7,
+	[FIRST_EXTERNAL_VECTOR + 8] = 8,
+	[FIRST_EXTERNAL_VECTOR + 9] = 9,
+	[FIRST_EXTERNAL_VECTOR + 10] = 10,
+	[FIRST_EXTERNAL_VECTOR + 11] = 11,
+	[FIRST_EXTERNAL_VECTOR + 12] = 12,
+	[FIRST_EXTERNAL_VECTOR + 13] = 13,
+	[FIRST_EXTERNAL_VECTOR + 14] = 14,
+	[FIRST_EXTERNAL_VECTOR + 15] = 15,
+	[FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1
+};
 
 void __init init_ISA_irqs (void)
 {
@@ -464,12 +431,13 @@
 			/*
 			 * 16 old-style INTA-cycle interrupts:
 			 */
-			irq_desc[i].chip = &i8259A_irq_type;
+			set_irq_chip_and_handler(i, &i8259A_chip,
+						 handle_level_irq);
 		} else {
 			/*
 			 * 'high' PCI IRQs filled in on demand
 			 */
-			irq_desc[i].chip = &no_irq_type;
+			irq_desc[i].chip = &no_irq_chip;
 		}
 	}
 }
@@ -543,8 +511,6 @@
 	 */
 	for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
 		int vector = FIRST_EXTERNAL_VECTOR + i;
-		if (i >= NR_IRQS)
-			break;
 		if (vector != IA32_SYSCALL_VECTOR)
 			set_intr_gate(vector, interrupt[i]);
 	}
@@ -554,7 +520,7 @@
 	 * IRQ0 must be given a fixed assignment and initialized,
 	 * because it's used before the IO-APIC is set up.
 	 */
-	set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
+	__get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0;
 
 	/*
 	 * The reschedule interrupt is a CPU-to-CPU reschedule-helper
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 0491019..91728d9 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -26,9 +26,12 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/smp_lock.h>
+#include <linux/pci.h>
 #include <linux/mc146818rtc.h>
 #include <linux/acpi.h>
 #include <linux/sysdev.h>
+#include <linux/msi.h>
+#include <linux/htirq.h>
 #ifdef CONFIG_ACPI
 #include <acpi/acpi_bus.h>
 #endif
@@ -41,6 +44,10 @@
 #include <asm/acpi.h>
 #include <asm/dma.h>
 #include <asm/nmi.h>
+#include <asm/msidef.h>
+#include <asm/hypertransport.h>
+
+static int assign_irq_vector(int irq, cpumask_t mask);
 
 #define __apicdebuginit  __init
 
@@ -81,14 +88,6 @@
 	short apic, pin, next;
 } irq_2_pin[PIN_MAP_SIZE];
 
-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
-#ifdef CONFIG_PCI_MSI
-#define vector_to_irq(vector) 	\
-	(platform_legacy_irq(vector) ? vector : vector_irq[vector])
-#else
-#define vector_to_irq(vector)	(vector)
-#endif
-
 #define __DO_ACTION(R, ACTION, FINAL)					\
 									\
 {									\
@@ -139,11 +138,35 @@
 }
 
 #ifdef CONFIG_SMP
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
+{
+	int apic, pin;
+	struct irq_pin_list *entry = irq_2_pin + irq;
+
+	BUG_ON(irq >= NR_IRQS);
+	for (;;) {
+		unsigned int reg;
+		apic = entry->apic;
+		pin = entry->pin;
+		if (pin == -1)
+			break;
+		io_apic_write(apic, 0x11 + pin*2, dest);
+		reg = io_apic_read(apic, 0x10 + pin*2);
+		reg &= ~0x000000ff;
+		reg |= vector;
+		io_apic_modify(apic, reg);
+		if (!entry->next)
+			break;
+		entry = irq_2_pin + entry->next;
+	}
+}
+
 static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
 {
 	unsigned long flags;
 	unsigned int dest;
 	cpumask_t tmp;
+	int vector;
 
 	cpus_and(tmp, mask, cpu_online_map);
 	if (cpus_empty(tmp))
@@ -151,7 +174,13 @@
 
 	cpus_and(mask, tmp, CPU_MASK_ALL);
 
-	dest = cpu_mask_to_apicid(mask);
+	vector = assign_irq_vector(irq, mask);
+	if (vector < 0)
+		return;
+
+	cpus_clear(tmp);
+	cpu_set(vector >> 8, tmp);
+	dest = cpu_mask_to_apicid(tmp);
 
 	/*
 	 * Only the high 8 bits are valid.
@@ -159,14 +188,12 @@
 	dest = SET_APIC_LOGICAL_ID(dest);
 
 	spin_lock_irqsave(&ioapic_lock, flags);
-	__DO_ACTION(1, = dest, )
-	set_irq_info(irq, mask);
+	__target_IO_APIC_irq(irq, dest, vector & 0xff);
+	set_native_irq_info(irq, mask);
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 #endif
 
-static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF };
-
 /*
  * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
  * shared ISA-space IRQs, so we have to support them. We are super
@@ -492,64 +519,6 @@
 	return MPBIOS_trigger(idx);
 }
 
-static int next_irq = 16;
-
-/*
- * gsi_irq_sharing -- Name overload!  "irq" can be either a legacy IRQ
- * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number
- * from ACPI, which can reach 800 in large boxen.
- *
- * Compact the sparse GSI space into a sequential IRQ series and reuse
- * vectors if possible.
- */
-int gsi_irq_sharing(int gsi)
-{
-	int i, tries, vector;
-
-	BUG_ON(gsi >= NR_IRQ_VECTORS);
-
-	if (platform_legacy_irq(gsi))
-		return gsi;
-
-	if (gsi_2_irq[gsi] != 0xFF)
-		return (int)gsi_2_irq[gsi];
-
-	tries = NR_IRQS;
-  try_again:
-	vector = assign_irq_vector(gsi);
-
-	/*
-	 * Sharing vectors means sharing IRQs, so scan irq_vectors for previous
-	 * use of vector and if found, return that IRQ.  However, we never want
-	 * to share legacy IRQs, which usually have a different trigger mode
-	 * than PCI.
-	 */
-	for (i = 0; i < NR_IRQS; i++)
-		if (IO_APIC_VECTOR(i) == vector)
-			break;
-	if (platform_legacy_irq(i)) {
-		if (--tries >= 0) {
-			IO_APIC_VECTOR(i) = 0;
-			goto try_again;
-		}
-		panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi);
-	}
-	if (i < NR_IRQS) {
-		gsi_2_irq[gsi] = i;
-		printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n",
-				gsi, vector, i);
-		return i;
-	}
-
-	i = next_irq++;
-	BUG_ON(i >= NR_IRQS);
-	gsi_2_irq[gsi] = i;
-	IO_APIC_VECTOR(i) = vector;
-	printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n",
-			gsi, vector, i);
-	return i;
-}
-
 static int pin_2_irq(int idx, int apic, int pin)
 {
 	int irq, i;
@@ -571,7 +540,6 @@
 		while (i < apic)
 			irq += nr_ioapic_registers[i++];
 		irq += pin;
-		irq = gsi_irq_sharing(irq);
 	}
 	BUG_ON(irq >= NR_IRQS);
 	return irq;
@@ -595,46 +563,83 @@
 }
 
 /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
+unsigned int irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_EXTERNAL_VECTOR, 0 };
 
-int assign_irq_vector(int irq)
+static int __assign_irq_vector(int irq, cpumask_t mask)
 {
-	static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
-	unsigned long flags;
-	int vector;
+	/*
+	 * NOTE! The local APIC isn't very good at handling
+	 * multiple interrupts at the same interrupt level.
+	 * As the interrupt level is determined by taking the
+	 * vector number and shifting that right by 4, we
+	 * want to spread these out a bit so that they don't
+	 * all fall in the same interrupt level.
+	 *
+	 * Also, we've got to be careful not to trash gate
+	 * 0x80, because int 0x80 is hm, kind of importantish. ;)
+	 */
+	static struct {
+		int vector;
+		int offset;
+	} pos[NR_CPUS] = { [ 0 ... NR_CPUS - 1] = {FIRST_DEVICE_VECTOR, 0} };
+	int old_vector = -1;
+	int cpu;
 
-	BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+	BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+
+	if (IO_APIC_VECTOR(irq) > 0)
+		old_vector = IO_APIC_VECTOR(irq);
+	if ((old_vector > 0) && cpu_isset(old_vector >> 8, mask)) {
+		return old_vector;
+	}
+
+	for_each_cpu_mask(cpu, mask) {
+		int vector, offset;
+		vector = pos[cpu].vector;
+		offset = pos[cpu].offset;
+next:
+		vector += 8;
+		if (vector >= FIRST_SYSTEM_VECTOR) {
+			/* If we run out of vectors on large boxen, must share them. */
+			offset = (offset + 1) % 8;
+			vector = FIRST_DEVICE_VECTOR + offset;
+		}
+		if (unlikely(pos[cpu].vector == vector))
+			continue;
+		if (vector == IA32_SYSCALL_VECTOR)
+			goto next;
+		if (per_cpu(vector_irq, cpu)[vector] != -1)
+			goto next;
+		/* Found one! */
+		pos[cpu].vector = vector;
+		pos[cpu].offset = offset;
+		if (old_vector >= 0) {
+			int old_cpu = old_vector >> 8;
+			old_vector &= 0xff;
+			per_cpu(vector_irq, old_cpu)[old_vector] = -1;
+		}
+		per_cpu(vector_irq, cpu)[vector] = irq;
+		vector |= cpu << 8;
+		IO_APIC_VECTOR(irq) = vector;
+		return vector;
+	}
+	return -ENOSPC;
+}
+
+static int assign_irq_vector(int irq, cpumask_t mask)
+{
+	int vector;
+	unsigned long flags;
 
 	spin_lock_irqsave(&vector_lock, flags);
-
-	if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
-		spin_unlock_irqrestore(&vector_lock, flags);
-		return IO_APIC_VECTOR(irq);
-	}
-next:
-	current_vector += 8;
-	if (current_vector == IA32_SYSCALL_VECTOR)
-		goto next;
-
-	if (current_vector >= FIRST_SYSTEM_VECTOR) {
-		/* If we run out of vectors on large boxen, must share them. */
-		offset = (offset + 1) % 8;
-		current_vector = FIRST_DEVICE_VECTOR + offset;
-	}
-
-	vector = current_vector;
-	vector_irq[vector] = irq;
-	if (irq != AUTO_ASSIGN)
-		IO_APIC_VECTOR(irq) = vector;
-
+	vector = __assign_irq_vector(irq, mask);
 	spin_unlock_irqrestore(&vector_lock, flags);
-
 	return vector;
 }
 
 extern void (*interrupt[NR_IRQS])(void);
-static struct hw_interrupt_type ioapic_level_type;
-static struct hw_interrupt_type ioapic_edge_type;
+
+static struct irq_chip ioapic_chip;
 
 #define IOAPIC_AUTO	-1
 #define IOAPIC_EDGE	0
@@ -642,16 +647,13 @@
 
 static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-	unsigned idx;
-
-	idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
-
 	if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
 			trigger == IOAPIC_LEVEL)
-		irq_desc[idx].chip = &ioapic_level_type;
+		set_irq_chip_and_handler(irq, &ioapic_chip,
+					 handle_fasteoi_irq);
 	else
-		irq_desc[idx].chip = &ioapic_edge_type;
-	set_intr_gate(vector, interrupt[idx]);
+		set_irq_chip_and_handler(irq, &ioapic_chip,
+					 handle_edge_irq);
 }
 
 static void __init setup_IO_APIC_irqs(void)
@@ -701,8 +703,15 @@
 			continue;
 
 		if (IO_APIC_IRQ(irq)) {
-			vector = assign_irq_vector(irq);
-			entry.vector = vector;
+			cpumask_t mask;
+			vector = assign_irq_vector(irq, TARGET_CPUS);
+			if (vector < 0)
+				continue;
+
+			cpus_clear(mask);
+			cpu_set(vector >> 8, mask);
+			entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
+			entry.vector = vector & 0xff;
 
 			ioapic_register_intr(irq, vector, IOAPIC_AUTO);
 			if (!apic && (irq < 16))
@@ -752,7 +761,7 @@
 	 * The timer IRQ doesn't have to know that behind the
 	 * scene we have a 8259A-master in AEOI mode ...
 	 */
-	irq_desc[0].chip = &ioapic_edge_type;
+	set_irq_chip_and_handler(0, &ioapic_chip, handle_edge_irq);
 
 	/*
 	 * Add it to the IO-APIC irq-routing table:
@@ -868,17 +877,12 @@
 		);
 	}
 	}
-	if (use_pci_vector())
-		printk(KERN_INFO "Using vector-based indexing\n");
 	printk(KERN_DEBUG "IRQ to pin mappings:\n");
 	for (i = 0; i < NR_IRQS; i++) {
 		struct irq_pin_list *entry = irq_2_pin + i;
 		if (entry->pin < 0)
 			continue;
- 		if (use_pci_vector() && !platform_legacy_irq(i))
-			printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
-		else
-			printk(KERN_DEBUG "IRQ%d ", i);
+		printk(KERN_DEBUG "IRQ%d ", i);
 		for (;;) {
 			printk("-> %d:%d", entry->apic, entry->pin);
 			if (!entry->next)
@@ -1185,7 +1189,7 @@
  * an edge even if it isn't on the 8259A...
  */
 
-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(unsigned int irq)
 {
 	int was_pending = 0;
 	unsigned long flags;
@@ -1202,107 +1206,16 @@
 	return was_pending;
 }
 
-/*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
-static void ack_edge_ioapic_irq(unsigned int irq)
+static int ioapic_retrigger_irq(unsigned int irq)
 {
-	move_irq(irq);
-	if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
-					== (IRQ_PENDING | IRQ_DISABLED))
-		mask_IO_APIC_irq(irq);
-	ack_APIC_irq();
-}
+	cpumask_t mask;
+	unsigned vector;
 
-/*
- * Level triggered interrupts can just be masked,
- * and shutting down and starting up the interrupt
- * is the same as enabling and disabling them -- except
- * with a startup need to return a "was pending" value.
- *
- * Level triggered interrupts are special because we
- * do not touch any IO-APIC register while handling
- * them. We ack the APIC in the end-IRQ handler, not
- * in the start-IRQ-handler. Protection against reentrance
- * from the same interrupt is still provided, both by the
- * generic IRQ layer and by the fact that an unacked local
- * APIC does not accept IRQs.
- */
-static unsigned int startup_level_ioapic_irq (unsigned int irq)
-{
-	unmask_IO_APIC_irq(irq);
+	vector = irq_vector[irq];
+	cpus_clear(mask);
+	cpu_set(vector >> 8, mask);
 
-	return 0; /* don't check for pending */
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
-{
-	move_irq(irq);
-	ack_APIC_irq();
-}
-
-#ifdef CONFIG_PCI_MSI
-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	return startup_edge_ioapic_irq(irq);
-}
-
-static void ack_edge_ioapic_vector(unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	move_native_irq(vector);
-	ack_edge_ioapic_irq(irq);
-}
-
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	return startup_level_ioapic_irq (irq);
-}
-
-static void end_level_ioapic_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	move_native_irq(vector);
-	end_level_ioapic_irq(irq);
-}
-
-static void mask_IO_APIC_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	mask_IO_APIC_irq(irq);
-}
-
-static void unmask_IO_APIC_vector (unsigned int vector)
-{
-	int irq = vector_to_irq(vector);
-
-	unmask_IO_APIC_irq(irq);
-}
-
-#ifdef CONFIG_SMP
-static void set_ioapic_affinity_vector (unsigned int vector,
-					cpumask_t cpu_mask)
-{
-	int irq = vector_to_irq(vector);
-
-	set_native_irq_info(vector, cpu_mask);
-	set_ioapic_affinity_irq(irq, cpu_mask);
-}
-#endif // CONFIG_SMP
-#endif // CONFIG_PCI_MSI
-
-static int ioapic_retrigger(unsigned int irq)
-{
-	send_IPI_self(IO_APIC_VECTOR(irq));
+	send_IPI_mask(mask, vector & 0xff);
 
 	return 1;
 }
@@ -1316,32 +1229,47 @@
  * races.
  */
 
-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
-	.typename = "IO-APIC-edge",
-	.startup 	= startup_edge_ioapic,
-	.shutdown 	= shutdown_edge_ioapic,
-	.enable 	= enable_edge_ioapic,
-	.disable 	= disable_edge_ioapic,
-	.ack 		= ack_edge_ioapic,
-	.end 		= end_edge_ioapic,
-#ifdef CONFIG_SMP
-	.set_affinity = set_ioapic_affinity,
-#endif
-	.retrigger	= ioapic_retrigger,
-};
+static void ack_apic_edge(unsigned int irq)
+{
+	move_native_irq(irq);
+	ack_APIC_irq();
+}
 
-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
-	.typename = "IO-APIC-level",
-	.startup 	= startup_level_ioapic,
-	.shutdown 	= shutdown_level_ioapic,
-	.enable 	= enable_level_ioapic,
-	.disable 	= disable_level_ioapic,
-	.ack 		= mask_and_ack_level_ioapic,
-	.end 		= end_level_ioapic,
-#ifdef CONFIG_SMP
-	.set_affinity = set_ioapic_affinity,
+static void ack_apic_level(unsigned int irq)
+{
+	int do_unmask_irq = 0;
+
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
+	/* If we are moving the irq we need to mask it */
+	if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+		do_unmask_irq = 1;
+		mask_IO_APIC_irq(irq);
+	}
 #endif
-	.retrigger	= ioapic_retrigger,
+
+	/*
+	 * We must acknowledge the irq before we move it or the acknowledge will
+	 * not propogate properly.
+	 */
+	ack_APIC_irq();
+
+	/* Now we can move and renable the irq */
+	move_masked_irq(irq);
+	if (unlikely(do_unmask_irq))
+		unmask_IO_APIC_irq(irq);
+}
+
+static struct irq_chip ioapic_chip __read_mostly = {
+	.name 		= "IO-APIC",
+	.startup 	= startup_ioapic_irq,
+	.mask	 	= mask_IO_APIC_irq,
+	.unmask	 	= unmask_IO_APIC_irq,
+	.ack 		= ack_apic_edge,
+	.eoi 		= ack_apic_level,
+#ifdef CONFIG_SMP
+	.set_affinity 	= set_ioapic_affinity_irq,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -1361,11 +1289,6 @@
 	 */
 	for (irq = 0; irq < NR_IRQS ; irq++) {
 		int tmp = irq;
-		if (use_pci_vector()) {
-			if (!platform_legacy_irq(tmp))
-				if ((tmp = vector_to_irq(tmp)) == -1)
-					continue;
-		}
 		if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
 			/*
 			 * Hmm.. We don't have an entry for this,
@@ -1376,7 +1299,7 @@
 				make_8259A_irq(irq);
 			else
 				/* Strange. Oh, well.. */
-				irq_desc[irq].chip = &no_irq_type;
+				irq_desc[irq].chip = &no_irq_chip;
 		}
 	}
 }
@@ -1495,8 +1418,6 @@
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-int timer_uses_ioapic_pin_0;
-
 /*
  * This code may look a bit paranoid, but it's supposed to cooperate with
  * a wide range of boards and BIOS bugs.  Fortunately only the timer IRQ
@@ -1514,8 +1435,7 @@
 	 * get/set the timer IRQ vector:
 	 */
 	disable_8259A_irq(0);
-	vector = assign_irq_vector(0);
-	set_intr_gate(vector, interrupt[0]);
+	vector = assign_irq_vector(0, TARGET_CPUS);
 
 	/*
 	 * Subtle, code in do_timer_interrupt() expects an AEOI
@@ -1534,9 +1454,6 @@
 	pin2  = ioapic_i8259.pin;
 	apic2 = ioapic_i8259.apic;
 
-	if (pin1 == 0)
-		timer_uses_ioapic_pin_0 = 1;
-
 	apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
 		vector, apic1, pin1, apic2, pin2);
 
@@ -1740,6 +1657,253 @@
 
 device_initcall(ioapic_init_sysfs);
 
+/*
+ * Dynamic irq allocate and deallocation
+ */
+int create_irq(void)
+{
+	/* Allocate an unused irq */
+	int irq;
+	int new;
+	int vector = 0;
+	unsigned long flags;
+
+	irq = -ENOSPC;
+	spin_lock_irqsave(&vector_lock, flags);
+	for (new = (NR_IRQS - 1); new >= 0; new--) {
+		if (platform_legacy_irq(new))
+			continue;
+		if (irq_vector[new] != 0)
+			continue;
+		vector = __assign_irq_vector(new, TARGET_CPUS);
+		if (likely(vector > 0))
+			irq = new;
+		break;
+	}
+	spin_unlock_irqrestore(&vector_lock, flags);
+
+	if (irq >= 0) {
+		dynamic_irq_init(irq);
+	}
+	return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+	unsigned long flags;
+
+	dynamic_irq_cleanup(irq);
+
+	spin_lock_irqsave(&vector_lock, flags);
+	irq_vector[irq] = 0;
+	spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+/*
+ * MSI mesage composition
+ */
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+{
+	int vector;
+	unsigned dest;
+
+	vector = assign_irq_vector(irq, TARGET_CPUS);
+	if (vector >= 0) {
+		cpumask_t tmp;
+
+		cpus_clear(tmp);
+		cpu_set(vector >> 8, tmp);
+		dest = cpu_mask_to_apicid(tmp);
+
+		msg->address_hi = MSI_ADDR_BASE_HI;
+		msg->address_lo =
+			MSI_ADDR_BASE_LO |
+			((INT_DEST_MODE == 0) ?
+				MSI_ADDR_DEST_MODE_PHYSICAL:
+				MSI_ADDR_DEST_MODE_LOGICAL) |
+			((INT_DELIVERY_MODE != dest_LowestPrio) ?
+				MSI_ADDR_REDIRECTION_CPU:
+				MSI_ADDR_REDIRECTION_LOWPRI) |
+			MSI_ADDR_DEST_ID(dest);
+
+		msg->data =
+			MSI_DATA_TRIGGER_EDGE |
+			MSI_DATA_LEVEL_ASSERT |
+			((INT_DELIVERY_MODE != dest_LowestPrio) ?
+				MSI_DATA_DELIVERY_FIXED:
+				MSI_DATA_DELIVERY_LOWPRI) |
+			MSI_DATA_VECTOR(vector);
+	}
+	return vector;
+}
+
+#ifdef CONFIG_SMP
+static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+	struct msi_msg msg;
+	unsigned int dest;
+	cpumask_t tmp;
+	int vector;
+
+	cpus_and(tmp, mask, cpu_online_map);
+	if (cpus_empty(tmp))
+		tmp = TARGET_CPUS;
+
+	cpus_and(mask, tmp, CPU_MASK_ALL);
+
+	vector = assign_irq_vector(irq, mask);
+	if (vector < 0)
+		return;
+
+	cpus_clear(tmp);
+	cpu_set(vector >> 8, tmp);
+	dest = cpu_mask_to_apicid(tmp);
+
+	read_msi_msg(irq, &msg);
+
+	msg.data &= ~MSI_DATA_VECTOR_MASK;
+	msg.data |= MSI_DATA_VECTOR(vector);
+	msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+	msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+	write_msi_msg(irq, &msg);
+	set_native_irq_info(irq, mask);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip msi_chip = {
+	.name		= "PCI-MSI",
+	.unmask		= unmask_msi_irq,
+	.mask		= mask_msi_irq,
+	.ack		= ack_apic_edge,
+#ifdef CONFIG_SMP
+	.set_affinity	= set_msi_irq_affinity,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
+};
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+{
+	struct msi_msg msg;
+	int ret;
+	ret = msi_compose_msg(dev, irq, &msg);
+	if (ret < 0)
+		return ret;
+
+	write_msi_msg(irq, &msg);
+
+	set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq);
+
+	return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+	return;
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+/*
+ * Hypertransport interrupt support
+ */
+#ifdef CONFIG_HT_IRQ
+
+#ifdef CONFIG_SMP
+
+static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
+{
+	u32 low, high;
+	low  = read_ht_irq_low(irq);
+	high = read_ht_irq_high(irq);
+
+	low  &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
+	high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+
+	low  |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
+	high |= HT_IRQ_HIGH_DEST_ID(dest);
+
+	write_ht_irq_low(irq, low);
+	write_ht_irq_high(irq, high);
+}
+
+static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+	unsigned int dest;
+	cpumask_t tmp;
+	int vector;
+
+	cpus_and(tmp, mask, cpu_online_map);
+	if (cpus_empty(tmp))
+		tmp = TARGET_CPUS;
+
+	cpus_and(mask, tmp, CPU_MASK_ALL);
+
+	vector = assign_irq_vector(irq, mask);
+	if (vector < 0)
+		return;
+
+	cpus_clear(tmp);
+	cpu_set(vector >> 8, tmp);
+	dest = cpu_mask_to_apicid(tmp);
+
+	target_ht_irq(irq, dest, vector & 0xff);
+	set_native_irq_info(irq, mask);
+}
+#endif
+
+static struct hw_interrupt_type ht_irq_chip = {
+	.name		= "PCI-HT",
+	.mask		= mask_ht_irq,
+	.unmask		= unmask_ht_irq,
+	.ack		= ack_apic_edge,
+#ifdef CONFIG_SMP
+	.set_affinity	= set_ht_irq_affinity,
+#endif
+	.retrigger	= ioapic_retrigger_irq,
+};
+
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+{
+	int vector;
+
+	vector = assign_irq_vector(irq, TARGET_CPUS);
+	if (vector >= 0) {
+		u32 low, high;
+		unsigned dest;
+		cpumask_t tmp;
+
+		cpus_clear(tmp);
+		cpu_set(vector >> 8, tmp);
+		dest = cpu_mask_to_apicid(tmp);
+
+		high = 	HT_IRQ_HIGH_DEST_ID(dest);
+
+		low =	HT_IRQ_LOW_BASE |
+			HT_IRQ_LOW_DEST_ID(dest) |
+			HT_IRQ_LOW_VECTOR(vector) |
+			((INT_DEST_MODE == 0) ?
+				HT_IRQ_LOW_DM_PHYSICAL :
+				HT_IRQ_LOW_DM_LOGICAL) |
+			HT_IRQ_LOW_RQEOI_EDGE |
+			((INT_DELIVERY_MODE != dest_LowestPrio) ?
+				HT_IRQ_LOW_MT_FIXED :
+				HT_IRQ_LOW_MT_ARBITRATED);
+
+		write_ht_irq_low(irq, low);
+		write_ht_irq_high(irq, high);
+
+		set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq);
+	}
+	return vector;
+}
+#endif /* CONFIG_HT_IRQ */
+
 /* --------------------------------------------------------------------------
                           ACPI-based IOAPIC Configuration
    -------------------------------------------------------------------------- */
@@ -1765,6 +1929,8 @@
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
+	int vector;
+	cpumask_t mask;
 
 	if (!IO_APIC_IRQ(irq)) {
 		apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
@@ -1773,6 +1939,20 @@
 	}
 
 	/*
+	 * IRQs < 16 are already in the irq_2_pin[] map
+	 */
+	if (irq >= 16)
+		add_pin_to_irq(irq, ioapic, pin);
+
+
+	vector = assign_irq_vector(irq, TARGET_CPUS);
+	if (vector < 0)
+		return vector;
+
+	cpus_clear(mask);
+	cpu_set(vector >> 8, mask);
+
+	/*
 	 * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
 	 * Note that we mask (disable) IRQs now -- these get enabled when the
 	 * corresponding device driver registers for this IRQ.
@@ -1782,19 +1962,11 @@
 
 	entry.delivery_mode = INT_DELIVERY_MODE;
 	entry.dest_mode = INT_DEST_MODE;
-	entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
+	entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
 	entry.trigger = triggering;
 	entry.polarity = polarity;
 	entry.mask = 1;					 /* Disabled (masked) */
-
-	irq = gsi_irq_sharing(irq);
-	/*
-	 * 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);
+	entry.vector = vector & 0xff;
 
 	apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
 		"IRQ %d Mode:%i Active:%i)\n", ioapic, 
@@ -1809,7 +1981,7 @@
 	ioapic_write_entry(ioapic, pin, entry);
 
 	spin_lock_irqsave(&ioapic_lock, flags);
-	set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
+	set_native_irq_info(irq, TARGET_CPUS);
 	spin_unlock_irqrestore(&ioapic_lock, flags);
 
 	return 0;
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index b3677e6..506f27c 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -74,7 +74,8 @@
 		for_each_online_cpu(j)
 			seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
-		seq_printf(p, " %14s", irq_desc[i].chip->typename);
+		seq_printf(p, " %8s", irq_desc[i].chip->name);
+		seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
 
 		seq_printf(p, "  %s", action->name);
 		for (action=action->next; action; action = action->next)
@@ -104,7 +105,12 @@
 asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 {	
 	/* high bit used in ret_from_ code  */
-	unsigned irq = ~regs->orig_rax;
+	unsigned vector = ~regs->orig_rax;
+	unsigned irq;
+
+	exit_idle();
+	irq_enter();
+	irq = __get_cpu_var(vector_irq)[vector];
 
 	if (unlikely(irq >= NR_IRQS)) {
 		printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
@@ -112,12 +118,10 @@
 		BUG();
 	}
 
-	exit_idle();
-	irq_enter();
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 	stack_overflow_check(regs);
 #endif
-	__do_IRQ(irq, regs);
+	generic_handle_irq(irq, regs);
 	irq_exit();
 
 	return 1;
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index b8d53df..b147ab1 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -790,20 +790,11 @@
 	}
 }
 
-#define MAX_GSI_NUM	4096
-
 int mp_register_gsi(u32 gsi, int triggering, int polarity)
 {
 	int ioapic = -1;
 	int ioapic_pin = 0;
 	int idx, bit = 0;
-	static int pci_irq = 16;
-	/*
-	 * Mapping between Global System Interrupts, which
-	 * represent all possible interrupts, to the IRQs
-	 * assigned to actual devices.
-	 */
-	static int gsi_to_irq[MAX_GSI_NUM];
 
 	if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
 		return gsi;
@@ -836,42 +827,11 @@
 	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);
-		return gsi_to_irq[gsi];
+		return gsi;
 	}
 
 	mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
 
-	if (triggering == ACPI_LEVEL_SENSITIVE) {
-		/*
-		 * For PCI devices assign IRQs in order, avoiding gaps
-		 * due to unused I/O APIC pins.
-		 */
-		int irq = gsi;
-		if (gsi < MAX_GSI_NUM) {
-			/*
-			 * Retain the VIA chipset work-around (gsi > 15), but
-			 * avoid a problem where the 8254 timer (IRQ0) is setup
-			 * via an override (so it's not on pin 0 of the ioapic),
-			 * and at the same time, the pin 0 interrupt is a PCI
-			 * type.  The gsi > 15 test could cause these two pins
-			 * to be shared as IRQ0, and they are not shareable.
-			 * So test for this condition, and if necessary, avoid
-			 * the pin collision.
-			 */
-			if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0))
-				gsi = pci_irq++;
-			/*
-			 * Don't assign IRQ used by ACPI SCI
-			 */
-			if (gsi == acpi_fadt.sci_int)
-				gsi = pci_irq++;
-			gsi_to_irq[irq] = gsi;
-		} else {
-			printk(KERN_ERR "GSI %u is too high\n", gsi);
-			return gsi;
-		}
-	}
-
 	io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
 		triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
 		polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index cfb09b0..f760045 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -21,7 +21,6 @@
  * 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>
diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c
index cbabfdf..f61fb8e 100644
--- a/arch/x86_64/kernel/tce.c
+++ b/arch/x86_64/kernel/tce.c
@@ -23,7 +23,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index c3454af..6d77e47 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -1,7 +1,6 @@
 /* Exports for assembly files.
    All C exports should go in the respective C files. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/smp.h>
 
diff --git a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S
index 0ebb03b..727a5d4 100644
--- a/arch/x86_64/lib/copy_page.S
+++ b/arch/x86_64/lib/copy_page.S
@@ -1,6 +1,5 @@
 /* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
-	
-#include <linux/config.h>
+
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 
diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c
index b6cd3cc..50be909 100644
--- a/arch/x86_64/lib/delay.c
+++ b/arch/x86_64/lib/delay.c
@@ -8,7 +8,6 @@
  *	depends wildly on alignment on many x86 processors. 
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
diff --git a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S
index 967b22f..0ea0ddc 100644
--- a/arch/x86_64/lib/memcpy.S
+++ b/arch/x86_64/lib/memcpy.S
@@ -1,6 +1,5 @@
 /* Copyright 2002 Andi Kleen */
-	
-#include <linux/config.h>
+
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 #include <asm/cpufeature.h>
diff --git a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S
index 09ed1f6..2c59481 100644
--- a/arch/x86_64/lib/memset.S
+++ b/arch/x86_64/lib/memset.S
@@ -1,6 +1,5 @@
 /* Copyright 2002 Andi Kleen, SuSE Labs */
 
-#include <linux/config.h>
 #include <linux/linkage.h>
 #include <asm/dwarf2.h>
 
diff --git a/arch/x86_64/lib/thunk.S b/arch/x86_64/lib/thunk.S
index 0025535..55e586d 100644
--- a/arch/x86_64/lib/thunk.S
+++ b/arch/x86_64/lib/thunk.S
@@ -5,7 +5,6 @@
  * Subject to the GNU public license, v.2. No warranty of any kind.
  */
 
-	#include <linux/config.h>
 	#include <linux/linkage.h>
 	#include <asm/dwarf2.h>
 	#include <asm/calling.h>			
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 1aabc81..54e1f38 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -299,76 +299,46 @@
 
 static const struct pci_device_id ahci_pci_tbl[] = {
 	/* Intel */
-	{ PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH6 */
-	{ PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH6M */
-	{ PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH7 */
-	{ PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH7M */
-	{ PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH7R */
-	{ PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ULi M5288 */
-	{ PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ESB2 */
-	{ PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ESB2 */
-	{ PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ESB2 */
-	{ PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH7-M DH */
-	{ PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH8 */
-	{ PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH8 */
-	{ PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH8 */
-	{ PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH8M */
-	{ PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ICH8M */
+	{ PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
+	{ PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
+	{ PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
+	{ PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
+	{ PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
+	{ PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */
+	{ PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
+	{ PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
+	{ PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
+	{ PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
+	{ PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+	{ PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+	{ PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+	{ PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+	{ PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
 
 	/* JMicron */
-	{ 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* JMicron JMB360 */
-	{ 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* JMicron JMB361 */
-	{ 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* JMicron JMB363 */
-	{ 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* JMicron JMB365 */
-	{ 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* JMicron JMB366 */
+	{ PCI_VDEVICE(JMICRON, 0x2360), board_ahci }, /* JMicron JMB360 */
+	{ PCI_VDEVICE(JMICRON, 0x2361), board_ahci }, /* JMicron JMB361 */
+	{ PCI_VDEVICE(JMICRON, 0x2363), board_ahci }, /* JMicron JMB363 */
+	{ PCI_VDEVICE(JMICRON, 0x2365), board_ahci }, /* JMicron JMB365 */
+	{ PCI_VDEVICE(JMICRON, 0x2366), board_ahci }, /* JMicron JMB366 */
 
 	/* ATI */
-	{ PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ATI SB600 non-raid */
-	{ PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* ATI SB600 raid */
+	{ PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
+	{ PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
 
 	/* VIA */
-	{ PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci_vt8251 }, /* VIA VT8251 */
+	{ PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
 
 	/* NVIDIA */
-	{ PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },		/* MCP65 */
-	{ PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },		/* MCP65 */
-	{ PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },		/* MCP65 */
-	{ PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci },		/* MCP65 */
+	{ PCI_VDEVICE(NVIDIA, 0x044c), board_ahci },		/* MCP65 */
+	{ PCI_VDEVICE(NVIDIA, 0x044d), board_ahci },		/* MCP65 */
+	{ PCI_VDEVICE(NVIDIA, 0x044e), board_ahci },		/* MCP65 */
+	{ PCI_VDEVICE(NVIDIA, 0x044f), board_ahci },		/* MCP65 */
 
 	/* SiS */
-	{ PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* SiS 966 */
-	{ PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* SiS 966 */
-	{ PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_ahci }, /* SiS 968 */
+	{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
+	{ PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
+	{ PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
 
 	{ }	/* terminate list */
 };
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index b4abd68..dce6565 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -2340,7 +2340,8 @@
 
 	if (status & ATA_BUSY)
 		ata_port_printk(ap, KERN_WARNING,
-				"port is slow to respond, please be patient\n");
+				"port is slow to respond, please be patient "
+				"(Status 0x%x)\n", status);
 
 	timeout = timer_start + tmout;
 	while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
@@ -2350,7 +2351,8 @@
 
 	if (status & ATA_BUSY) {
 		ata_port_printk(ap, KERN_ERR, "port failed to respond "
-				"(%lu secs)\n", tmout / HZ);
+				"(%lu secs, Status 0x%x)\n",
+				tmout / HZ, status);
 		return 1;
 	}
 
@@ -5478,11 +5480,10 @@
 		int irq_line = ent->irq;
 
 		ap = ata_port_add(ent, host, i);
+		host->ports[i] = ap;
 		if (!ap)
 			goto err_out;
 
-		host->ports[i] = ap;
-
 		/* dummy? */
 		if (ent->dummy_port_mask & (1 << i)) {
 			ata_port_printk(ap, KERN_INFO, "DUMMY\n");
@@ -5740,7 +5741,7 @@
 
 /**
  *	ata_scsi_release - SCSI layer callback hook for host unload
- *	@host: libata host to be unloaded
+ *	@shost: libata host to be unloaded
  *
  *	Performs all duties necessary to shut down a libata port...
  *	Kill port kthread, disable port, and release resources.
@@ -5786,6 +5787,7 @@
 	probe_ent->mwdma_mask = port->mwdma_mask;
 	probe_ent->udma_mask = port->udma_mask;
 	probe_ent->port_ops = port->port_ops;
+	probe_ent->private_data = port->private_data;
 
 	return probe_ent;
 }
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3986ec8..b0d0cc4 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -889,6 +889,7 @@
 {
 	struct ata_port *ap = ata_shost_to_port(sdev->host);
 	struct ata_device *dev;
+	unsigned long flags;
 	int max_depth;
 
 	if (queue_depth < 1)
@@ -904,6 +905,14 @@
 		queue_depth = max_depth;
 
 	scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+
+	spin_lock_irqsave(ap->lock, flags);
+	if (queue_depth > 1)
+		dev->flags &= ~ATA_DFLAG_NCQ_OFF;
+	else
+		dev->flags |= ATA_DFLAG_NCQ_OFF;
+	spin_unlock_irqrestore(ap->lock, flags);
+
 	return queue_depth;
 }
 
@@ -1293,7 +1302,8 @@
 		 */
 		goto nothing_to_do;
 
-	if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+	if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
+			   ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
 		/* yay, NCQ */
 		if (!lba_48_ok(block, n_block))
 			goto out_of_range;
@@ -3174,7 +3184,7 @@
 
 /**
  *	ata_sas_port_alloc - Allocate port for a SAS attached SATA device
- *	@pdev: PCI device that the scsi device is attached to
+ *	@host: ATA host container for all SAS ports
  *	@port_info: Information from low-level host driver
  *	@shost: SCSI host that the scsi device is attached to
  *
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 08b3a40..06daaa3 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -828,7 +828,6 @@
 
 	probe_ent->irq = pdev->irq;
 	probe_ent->irq_flags = IRQF_SHARED;
-	probe_ent->private_data = port[0]->private_data;
 
 	if (ports & ATA_PORT_PRIMARY) {
 		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
@@ -878,7 +877,6 @@
 		return NULL;
 
 	probe_ent->n_ports = 2;
-	probe_ent->private_data = port[0]->private_data;
 
 	if (port_mask & ATA_PORT_PRIMARY) {
 		probe_ent->irq = ATA_PRIMARY_IRQ;
@@ -908,6 +906,8 @@
 				probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
 		}
 		ata_std_ports(&probe_ent->port[1]);
+
+		/* FIXME: could be pointing to stack area; must copy */
 		probe_ent->pinfo2 = port[1];
 	} else
 		probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
@@ -946,35 +946,21 @@
 {
 	struct ata_probe_ent *probe_ent = NULL;
 	struct ata_port_info *port[2];
-	u8 tmp8, mask;
+	u8 mask;
 	unsigned int legacy_mode = 0;
 	int disable_dev_on_err = 1;
 	int rc;
 
 	DPRINTK("ENTER\n");
 
+	BUG_ON(n_ports < 1 || n_ports > 2);
+
 	port[0] = port_info[0];
 	if (n_ports > 1)
 		port[1] = port_info[1];
 	else
 		port[1] = port[0];
 
-	if ((port[0]->flags & ATA_FLAG_NO_LEGACY) == 0
-	    && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		/* TODO: What if one channel is in native mode ... */
-		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
-		mask = (1 << 2) | (1 << 0);
-		if ((tmp8 & mask) != mask)
-			legacy_mode = (1 << 3);
-	}
-
-	/* FIXME... */
-	if ((!legacy_mode) && (n_ports > 2)) {
-		printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
-		n_ports = 2;
-		/* For now */
-	}
-
 	/* FIXME: Really for ATA it isn't safe because the device may be
 	   multi-purpose and we want to leave it alone if it was already
 	   enabled. Secondly for shared use as Arjan says we want refcounting
@@ -987,6 +973,16 @@
 	if (rc)
 		return rc;
 
+	if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		u8 tmp8;
+
+		/* TODO: What if one channel is in native mode ... */
+		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+		mask = (1 << 2) | (1 << 0);
+		if ((tmp8 & mask) != mask)
+			legacy_mode = (1 << 3);
+	}
+
 	rc = pci_request_regions(pdev, DRV_NAME);
 	if (rc) {
 		disable_dev_on_err = 0;
@@ -1039,7 +1035,7 @@
 		goto err_out_regions;
 	}
 
-	/* FIXME: If we get no DMA mask we should fall back to PIO */
+	/* TODO: If we get no DMA mask we should fall back to PIO */
 	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
 	if (rc)
 		goto err_out_regions;
@@ -1062,13 +1058,17 @@
 
 	pci_set_master(pdev);
 
-	/* FIXME: check ata_device_add return */
-	ata_device_add(probe_ent);
+	if (!ata_device_add(probe_ent)) {
+		rc = -ENODEV;
+		goto err_out_ent;
+	}
 
 	kfree(probe_ent);
 
 	return 0;
 
+err_out_ent:
+	kfree(probe_ent);
 err_out_regions:
 	if (legacy_mode & ATA_PORT_PRIMARY)
 		release_region(ATA_PRIMARY_CMD, 8);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 87af3b5..1d695df 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@
 #include <linux/dmi.h>
 
 #define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.6.5"
+#define DRV_VERSION "0.6.6"
 
 /*
  *	Cable special cases
@@ -630,7 +630,7 @@
 		pci_read_config_byte(pdev, 0x53, &tmp);
 		if (rev <= 0x20)
 			tmp &= ~0x02;
-		if (rev == 0xc7)
+		if (rev >= 0xc7)
 			tmp |= 0x03;
 		else
 			tmp |= 0x01;	/* CD_ROM enable for DMA */
@@ -644,10 +644,11 @@
 	return ata_pci_init_one(pdev, port_info, 2);
 }
 
-static struct pci_device_id ali[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229), },
-	{ 0, },
+static const struct pci_device_id ali[] = {
+	{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), },
+	{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), },
+
+	{ },
 };
 
 static struct pci_driver ali_pci_driver = {
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 599ee26..29234c8 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -662,27 +662,28 @@
 }
 
 static const struct pci_device_id amd[] = {
-	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_COBRA_7401,		PCI_ANY_ID, PCI_ANY_ID, 0, 0,  0 },
-	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7409,		PCI_ANY_ID, PCI_ANY_ID, 0, 0,  1 },
-	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_VIPER_7411,		PCI_ANY_ID, PCI_ANY_ID, 0, 0,  3 },
-	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_OPUS_7441,		PCI_ANY_ID, PCI_ANY_ID, 0, 0,  4 },
-	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_8111_IDE,		PCI_ANY_ID, PCI_ANY_ID, 0, 0,  5 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  7 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0,  8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE,	PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
-	{ PCI_VENDOR_ID_AMD,	PCI_DEVICE_ID_AMD_CS5536_IDE,		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
-	{ 0, },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_COBRA_7401),		0 },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_VIPER_7409),		1 },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_VIPER_7411),		3 },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_OPUS_7441),		4 },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_8111_IDE),		5 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_IDE),	7 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE),	8 },
+	{ PCI_VDEVICE(NVIDIA,	PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE),	8 },
+	{ PCI_VDEVICE(AMD,	PCI_DEVICE_ID_AMD_CS5536_IDE),		9 },
+
+	{ },
 };
 
 static struct pci_driver amd_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= amd,
 	.probe 		= amd_init_one,
 	.remove		= ata_pci_remove_one
@@ -698,7 +699,6 @@
 	pci_unregister_driver(&amd_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for AMD PATA IDE");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index c4ccb75..690828e 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -426,7 +426,7 @@
 		.port_ops	= &artop6260_ops,
 	};
 	struct ata_port_info *port_info[2];
-	struct ata_port_info *info;
+	struct ata_port_info *info = NULL;
 	int ports = 2;
 
 	if (!printed_version++)
@@ -470,16 +470,20 @@
 		pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
 
 	}
+
+	BUG_ON(info == NULL);
+
 	port_info[0] = port_info[1] = info;
 	return ata_pci_init_one(pdev, port_info, ports);
 }
 
 static const struct pci_device_id artop_pci_tbl[] = {
-	{ 0x1191, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ 0x1191, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-	{ 0x1191, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-	{ 0x1191, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
-	{ 0x1191, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{ PCI_VDEVICE(ARTOP, 0x0005), 0 },
+	{ PCI_VDEVICE(ARTOP, 0x0006), 1 },
+	{ PCI_VDEVICE(ARTOP, 0x0007), 1 },
+	{ PCI_VDEVICE(ARTOP, 0x0008), 2 },
+	{ PCI_VDEVICE(ARTOP, 0x0009), 2 },
+
 	{ }	/* terminate list */
 };
 
@@ -500,7 +504,6 @@
 	pci_unregister_driver(&artop_pci_driver);
 }
 
-
 module_init(artop_init);
 module_exit(artop_exit);
 
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 6c2269b..1ce28d2 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -267,12 +267,13 @@
 	return ata_pci_init_one(dev, port_info, 2);
 }
 
-static struct pci_device_id atiixp[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
-	{ 0, },
+static const struct pci_device_id atiixp[] = {
+	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
+	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
+	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
+	{ PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
+
+	{ },
 };
 
 static struct pci_driver atiixp_pci_driver = {
@@ -293,7 +294,6 @@
 	pci_unregister_driver(&atiixp_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index e92b0ef..b9bbd1d 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -468,16 +468,17 @@
 	return ata_pci_init_one(pdev, port_info, 2);
 }
 
-static struct pci_device_id cmd64x[] = {
-	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
-	{ PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
-	{ 0, },
+static const struct pci_device_id cmd64x[] = {
+	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
+	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
+	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
+	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
+
+	{ },
 };
 
 static struct pci_driver cmd64x_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= cmd64x,
 	.probe 		= cmd64x_init_one,
 	.remove		= ata_pci_remove_one
@@ -488,13 +489,11 @@
 	return pci_register_driver(&cmd64x_pci_driver);
 }
 
-
 static void __exit cmd64x_exit(void)
 {
 	pci_unregister_driver(&cmd64x_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index a6c6ceb..2cd3c0f 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -299,10 +299,11 @@
 /* For now keep DMA off. We can set it for all but A rev CS5510 once the
    core ATA code can handle it */
 
-static struct pci_device_id pata_cs5520[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
-	{ 0, },
+static const struct pci_device_id pata_cs5520[] = {
+	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
+	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
+
+	{ },
 };
 
 static struct pci_driver cs5520_pci_driver = {
@@ -312,7 +313,6 @@
 	.remove		= cs5520_remove_one
 };
 
-
 static int __init cs5520_init(void)
 {
 	return pci_register_driver(&cs5520_pci_driver);
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 7bba4d95..a07cc81 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -353,13 +353,14 @@
 	return -ENODEV;
 }
 
-static struct pci_device_id cs5530[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
-	{ 0, },
+static const struct pci_device_id cs5530[] = {
+	{ PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
+
+	{ },
 };
 
 static struct pci_driver cs5530_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= cs5530,
 	.probe 		= cs5530_init_one,
 	.remove		= ata_pci_remove_one
@@ -370,13 +371,11 @@
 	return pci_register_driver(&cs5530_pci_driver);
 }
 
-
 static void __exit cs5530_exit(void)
 {
 	pci_unregister_driver(&cs5530_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index d64fcdc..f8def3f 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -257,9 +257,10 @@
 	return ata_pci_init_one(dev, ports, 1);
 }
 
-static struct pci_device_id cs5535[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), },
-	{ 0, },
+static const struct pci_device_id cs5535[] = {
+	{ PCI_VDEVICE(NS, 0x002D), },
+
+	{ },
 };
 
 static struct pci_driver cs5535_pci_driver = {
@@ -274,13 +275,11 @@
 	return pci_register_driver(&cs5535_pci_driver);
 }
 
-
 static void __exit cs5535_exit(void)
 {
 	pci_unregister_driver(&cs5535_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch");
 MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index dfa5ac5..247b436 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -184,8 +184,8 @@
 	};
 	static struct ata_port_info *port_info[1] = { &info };
 
-	/* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. For the
-	   moment we don't handle the secondary. FIXME */
+	/* Devfn 1 is the ATA primary. The secondary is magic and on devfn2.
+	   For the moment we don't handle the secondary. FIXME */
 
 	if (PCI_FUNC(pdev->devfn) != 1)
 		return -ENODEV;
@@ -193,13 +193,14 @@
 	return ata_pci_init_one(pdev, port_info, 1);
 }
 
-static struct pci_device_id cy82c693[] = {
-	{ PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ 0, },
+static const struct pci_device_id cy82c693[] = {
+	{ PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), },
+
+	{ },
 };
 
 static struct pci_driver cy82c693_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= cy82c693,
 	.probe 		= cy82c693_init_one,
 	.remove		= ata_pci_remove_one
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index 95cd1ca..ef18c60 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -305,7 +305,8 @@
 }
 
 static const struct pci_device_id efar_pci_tbl[] = {
-	{ 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VDEVICE(EFAR, 0x9130), },
+
 	{ }	/* terminate list */
 };
 
@@ -326,7 +327,6 @@
 	pci_unregister_driver(&efar_pci_driver);
 }
 
-
 module_init(efar_init);
 module_exit(efar_exit);
 
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 8c75743..6d3e4c0 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -444,13 +444,14 @@
 	return ata_pci_init_one(dev, port_info, 2);
 }
 
-static struct pci_device_id hpt36x[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
-	{ 0, },
+static const struct pci_device_id hpt36x[] = {
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+
+	{ },
 };
 
 static struct pci_driver hpt36x_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= hpt36x,
 	.probe 		= hpt36x_init_one,
 	.remove		= ata_pci_remove_one
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 10318c0..7350443 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -1219,17 +1219,18 @@
 	return ata_pci_init_one(dev, port_info, 2);
 }
 
-static struct pci_device_id hpt37x[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
-	{ 0, },
+static const struct pci_device_id hpt37x[] = {
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), },
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), },
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
+
+	{ },
 };
 
 static struct pci_driver hpt37x_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= hpt37x,
 	.probe 		= hpt37x_init_one,
 	.remove		= ata_pci_remove_one
@@ -1240,13 +1241,11 @@
 	return pci_register_driver(&hpt37x_pci_driver);
 }
 
-
 static void __exit hpt37x_exit(void)
 {
 	pci_unregister_driver(&hpt37x_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 5c5d4f6..58cfb2b 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -560,16 +560,17 @@
 	return ata_pci_init_one(dev, port_info, 2);
 }
 
-static struct pci_device_id hpt3x2n[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N), },
-	{ 0, },
+static const struct pci_device_id hpt3x2n[] = {
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
+
+	{ },
 };
 
 static struct pci_driver hpt3x2n_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= hpt3x2n,
 	.probe 		= hpt3x2n_init_one,
 	.remove		= ata_pci_remove_one
@@ -580,13 +581,11 @@
 	return pci_register_driver(&hpt3x2n_pci_driver);
 }
 
-
 static void __exit hpt3x2n_exit(void)
 {
 	pci_unregister_driver(&hpt3x2n_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 1f084ab..3334d72 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -192,13 +192,14 @@
 	return ata_pci_init_one(dev, port_info, 2);
 }
 
-static struct pci_device_id hpt3x3[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), },
-	{ 0, },
+static const struct pci_device_id hpt3x3[] = {
+	{ PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), },
+
+	{ },
 };
 
 static struct pci_driver hpt3x3_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= hpt3x3,
 	.probe 		= hpt3x3_init_one,
 	.remove		= ata_pci_remove_one
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index 82a46ff..18ff3e5 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -808,14 +808,15 @@
 	return ata_pci_init_one(pdev, port_info, 2);
 }
 
-static struct pci_device_id it821x[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212), },
-	{ 0, },
+static const struct pci_device_id it821x[] = {
+	{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
+	{ PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
+
+	{ },
 };
 
 static struct pci_driver it821x_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= it821x,
 	.probe 		= it821x_init_one,
 	.remove		= ata_pci_remove_one
@@ -826,13 +827,11 @@
 	return pci_register_driver(&it821x_pci_driver);
 }
 
-
 static void __exit it821x_exit(void)
 {
 	pci_unregister_driver(&it821x_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index be3a866..52a2bdf 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -229,11 +229,12 @@
 }
 
 static const struct pci_device_id jmicron_pci_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
-	{ PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
-	{ PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
-	{ PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
-	{ PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
+	{ PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+
 	{ }	/* terminate list */
 };
 
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 3c65393..9dfe3e9 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -274,11 +274,10 @@
 	dev_set_drvdata(dev, NULL);
 }
 
-
-
 static const struct pci_device_id mpiix[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
-	{ 0, },
+	{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
+
+	{ },
 };
 
 static struct pci_driver mpiix_pci_driver = {
@@ -293,13 +292,11 @@
 	return pci_register_driver(&mpiix_pci_driver);
 }
 
-
 static void __exit mpiix_exit(void)
 {
 	pci_unregister_driver(&mpiix_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for Intel MPIIX");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 76eb9c9..f5672de 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -142,7 +142,8 @@
 }
 
 static const struct pci_device_id netcell_pci_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+	{ PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+
 	{ }	/* terminate list */
 };
 
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 2005a95..2a3dbee 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -200,12 +200,13 @@
 }
 
 static const struct pci_device_id ns87410[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410), },
-	{ 0, },
+	{ PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), },
+
+	{ },
 };
 
 static struct pci_driver ns87410_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= ns87410,
 	.probe 		= ns87410_init_one,
 	.remove		= ata_pci_remove_one
@@ -216,13 +217,11 @@
 	return pci_register_driver(&ns87410_pci_driver);
 }
 
-
 static void __exit ns87410_exit(void)
 {
 	pci_unregister_driver(&ns87410_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for Nat Semi 87410");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 31a285c..fc947df 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -303,7 +303,8 @@
 }
 
 static const struct pci_device_id oldpiix_pci_tbl[] = {
-	{ PCI_DEVICE(0x8086, 0x1230), },
+	{ PCI_VDEVICE(INTEL, 0x1230), },
+
 	{ }	/* terminate list */
 };
 
@@ -324,7 +325,6 @@
 	pci_unregister_driver(&oldpiix_pci_driver);
 }
 
-
 module_init(oldpiix_init);
 module_exit(oldpiix_exit);
 
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index 57fe21f..a7320ba 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -256,13 +256,14 @@
 }
 
 static const struct pci_device_id opti[] = {
-	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
-	{ PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
-	{ 0, },
+	{ PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
+	{ PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
+
+	{ },
 };
 
 static struct pci_driver opti_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= opti,
 	.probe 		= opti_init_one,
 	.remove		= ata_pci_remove_one
@@ -273,7 +274,6 @@
 	return pci_register_driver(&opti_pci_driver);
 }
 
-
 static void __exit opti_exit(void)
 {
 	pci_unregister_driver(&opti_pci_driver);
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 7296a20..c6906b4 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -512,12 +512,13 @@
 }
 
 static const struct pci_device_id optidma[] = {
-	{ PCI_DEVICE(0x1045, 0xD568), },	/* Opti 82C700 */
-	{ 0, },
+	{ PCI_VDEVICE(OPTI, 0xD568), },		/* Opti 82C700 */
+
+	{ },
 };
 
 static struct pci_driver optidma_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= optidma,
 	.probe 		= optidma_init_one,
 	.remove		= ata_pci_remove_one
@@ -528,13 +529,11 @@
 	return pci_register_driver(&optidma_pci_driver);
 }
 
-
 static void __exit optidma_exit(void)
 {
 	pci_unregister_driver(&optidma_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index cb501e1..e93ea27 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
 
 
 #define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.2.9"
+#define DRV_VERSION "0.2.11"
 
 /*
  *	Private data structure to glue stuff together
@@ -355,6 +355,8 @@
 	PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
 	PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
 	PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+	PCMCIA_DEVICE_PROD_ID1("TRANSCEND    512M   ", 0xd0909443),
+	PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
 	PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
 	PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
 	PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index bd4ed67..d894d99 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -108,13 +108,14 @@
 };
 
 static const struct pci_device_id pdc2027x_pci_tbl[] = {
-	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
-	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
-	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
-	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
-	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
-	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
-	{ PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), PDC_UDMA_100 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), PDC_UDMA_133 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), PDC_UDMA_100 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), PDC_UDMA_133 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), PDC_UDMA_133 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), PDC_UDMA_133 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), PDC_UDMA_133 },
+
 	{ }	/* terminate list */
 };
 
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 48f4343..5ba9eb2 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -385,17 +385,18 @@
 	return ata_pci_init_one(dev, port_info, 2);
 }
 
-static struct pci_device_id pdc[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0},
-	{ PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1},
-	{ PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1},
-	{ PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2},
-	{ PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2},
-	{ 0, },
+static const struct pci_device_id pdc[] = {
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
+	{ PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
+
+	{ },
 };
 
 static struct pci_driver pdc_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= pdc,
 	.probe 		= pdc_init_one,
 	.remove		= ata_pci_remove_one
@@ -406,13 +407,11 @@
 	return pci_register_driver(&pdc_pci_driver);
 }
 
-
 static void __exit pdc_exit(void)
 {
 	pci_unregister_driver(&pdc_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index c20bcf4..1af83d7 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -300,7 +300,8 @@
 }
 
 static const struct pci_device_id radisys_pci_tbl[] = {
-	{ 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VDEVICE(RADISYS, 0x8201), },
+
 	{ }	/* terminate list */
 };
 
@@ -321,7 +322,6 @@
 	pci_unregister_driver(&radisys_pci_driver);
 }
 
-
 module_init(radisys_init);
 module_exit(radisys_exit);
 
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index eccc6fd..4533b63 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -170,20 +170,20 @@
 	return -ENODEV;
 }
 
-static struct pci_device_id pata_rz1000[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
-	{ 0, },
+static const struct pci_device_id pata_rz1000[] = {
+	{ PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
+	{ PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
+
+	{ },
 };
 
 static struct pci_driver rz1000_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= pata_rz1000,
 	.probe 		= rz1000_init_one,
 	.remove		= ata_pci_remove_one
 };
 
-
 static int __init rz1000_init(void)
 {
 	return pci_register_driver(&rz1000_pci_driver);
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 107e6cd..067d9d2 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -253,13 +253,14 @@
 	return ata_pci_init_one(dev, port_info, 1);
 }
 
-static struct pci_device_id sc1200[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
-	{ 0, },
+static const struct pci_device_id sc1200[] = {
+	{ PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
+
+	{ },
 };
 
 static struct pci_driver sc1200_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= sc1200,
 	.probe 		= sc1200_init_one,
 	.remove		= ata_pci_remove_one
@@ -270,13 +271,11 @@
 	return pci_register_driver(&sc1200_pci_driver);
 }
 
-
 static void __exit sc1200_exit(void)
 {
 	pci_unregister_driver(&sc1200_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox, Mark Lord");
 MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index a5c8d7e..5bbf76e 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -553,13 +553,14 @@
 	return ata_pci_init_one(pdev, port_info, ports);
 }
 
-static struct pci_device_id serverworks[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
-	{ PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
-	{ 0, },
+static const struct pci_device_id serverworks[] = {
+	{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
+	{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
+	{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
+	{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
+	{ PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
+
+	{ },
 };
 
 static struct pci_driver serverworks_pci_driver = {
@@ -574,13 +575,11 @@
 	return pci_register_driver(&serverworks_pci_driver);
 }
 
-
 static void __exit serverworks_exit(void)
 {
 	pci_unregister_driver(&serverworks_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index c8b2e26..4a2b72b 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -348,12 +348,13 @@
 }
 
 static const struct pci_device_id sil680[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), },
-	{ 0, },
+	{ PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
+
+	{ },
 };
 
 static struct pci_driver sil680_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= sil680,
 	.probe 		= sil680_init_one,
 	.remove		= ata_pci_remove_one
@@ -364,13 +365,11 @@
 	return pci_register_driver(&sil680_pci_driver);
 }
 
-
 static void __exit sil680_exit(void)
 {
 	pci_unregister_driver(&sil680_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for SI680 PATA");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 17791e2..b9ffafb 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -988,8 +988,9 @@
 }
 
 static const struct pci_device_id sis_pci_tbl[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5513), },	/* SiS 5513 */
-	{ PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5518), },	/* SiS 5518 */
+	{ PCI_VDEVICE(SI, 0x5513), },	/* SiS 5513 */
+	{ PCI_VDEVICE(SI, 0x5518), },	/* SiS 5518 */
+
 	{ }
 };
 
@@ -1010,7 +1011,6 @@
 	pci_unregister_driver(&sis_pci_driver);
 }
 
-
 module_init(sis_init);
 module_exit(sis_exit);
 
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index 5b762ac..08a6dc8 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -351,9 +351,10 @@
 	return ata_pci_init_one(dev, port_info, 1); /* For now */
 }
 
-static struct pci_device_id sl82c105[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
-	{ 0, },
+static const struct pci_device_id sl82c105[] = {
+	{ PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
+
+	{ },
 };
 
 static struct pci_driver sl82c105_pci_driver = {
@@ -368,13 +369,11 @@
 	return pci_register_driver(&sl82c105_pci_driver);
 }
 
-
 static void __exit sl82c105_exit(void)
 {
 	pci_unregister_driver(&sl82c105_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for Sl82c105");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index a954ed9..9640f80 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -248,13 +248,13 @@
 }
 
 static const struct pci_device_id triflex[] = {
-	{ PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
-				  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-	{ 0, },
+	{ PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
+
+	{ },
 };
 
 static struct pci_driver triflex_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= triflex,
 	.probe 		= triflex_init_one,
 	.remove		= ata_pci_remove_one
@@ -265,13 +265,11 @@
 	return pci_register_driver(&triflex_pci_driver);
 }
 
-
 static void __exit triflex_exit(void)
 {
 	pci_unregister_driver(&triflex_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 7b5dd23..1e7be9e 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -529,15 +529,16 @@
 }
 
 static const struct pci_device_id via[] = {
-	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410), },
-	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
-	{ 0, },
+	{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), },
+	{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), },
+	{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), },
+	{ PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
+
+	{ },
 };
 
 static struct pci_driver via_pci_driver = {
-        .name 		= DRV_NAME,
+	.name 		= DRV_NAME,
 	.id_table	= via,
 	.probe 		= via_init_one,
 	.remove		= ata_pci_remove_one
@@ -548,13 +549,11 @@
 	return pci_register_driver(&via_pci_driver);
 }
 
-
 static void __exit via_exit(void)
 {
 	pci_unregister_driver(&via_pci_driver);
 }
 
-
 MODULE_AUTHOR("Alan Cox");
 MODULE_DESCRIPTION("low-level driver for VIA PATA");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 0e23ecb..81f3d21 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -192,8 +192,7 @@
 };
 
 static const struct pci_device_id adma_ata_pci_tbl[] = {
-	{ PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_1841_idx },
+	{ PCI_VDEVICE(PDC, 0x1841), board_1841_idx },
 
 	{ }	/* terminate list */
 };
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index c01496d..e6aa1a8 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -533,19 +533,20 @@
 };
 
 static const struct pci_device_id mv_pci_tbl[] = {
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
+	{ PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
+	{ PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
+	{ PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
+	{ PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
 
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
-	{PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
+	{ PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
+	{ PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
+	{ PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
+	{ PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
+	{ PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
 
-	{PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
-	{}			/* terminate list */
+	{ PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
+
+	{ }			/* terminate list */
 };
 
 static struct pci_driver mv_pci_driver = {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 8cd730f..d09d20a 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -106,45 +106,32 @@
 };
 
 static const struct pci_device_id nv_pci_tbl[] = {
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
-	{ PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), NFORCE2 },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), NFORCE3 },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), NFORCE3 },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA), CK804 },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, 0x045c), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, 0x045d), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, 0x045e), GENERIC },
+	{ PCI_VDEVICE(NVIDIA, 0x045f), GENERIC },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
 		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
 		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
-	{ 0, } /* terminate list */
+
+	{ } /* terminate list */
 };
 
 static struct pci_driver nv_pci_driver = {
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index d627812..15c9437 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -234,48 +234,31 @@
 };
 
 static const struct pci_device_id pdc_ata_pci_tbl[] = {
-	{ PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2057x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2057x },
-	{ PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2037x },
+	{ PCI_VDEVICE(PROMISE, 0x3371), board_2037x },
+	{ PCI_VDEVICE(PROMISE, 0x3570), board_2037x },
+	{ PCI_VDEVICE(PROMISE, 0x3571), board_2037x },
+	{ PCI_VDEVICE(PROMISE, 0x3373), board_2037x },
+	{ PCI_VDEVICE(PROMISE, 0x3375), board_2037x },
+	{ PCI_VDEVICE(PROMISE, 0x3376), board_2037x },
+	{ PCI_VDEVICE(PROMISE, 0x3574), board_2057x },
+	{ PCI_VDEVICE(PROMISE, 0x3d75), board_2057x },
+	{ PCI_VDEVICE(PROMISE, 0x3d73), board_2037x },
 
-	{ PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20319 },
-	{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20319 },
-	{ PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20319 },
-	{ PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20319 },
-	{ PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20319 },
-	{ PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_40518 },
+	{ PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
+	{ PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
+	{ PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
+	{ PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
+	{ PCI_VDEVICE(PROMISE, 0x3d17), board_20319 },
+	{ PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
 
-	{ PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20619 },
+	{ PCI_VDEVICE(PROMISE, 0x6629), board_20619 },
 
 /* TODO: remove all associated board_20771 code, as it completely
  * duplicates board_2037x code, unless reason for separation can be
  * divined.
  */
 #if 0
-	{ PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20771 },
+	{ PCI_VDEVICE(PROMISE, 0x3570), board_20771 },
 #endif
 
 	{ }	/* terminate list */
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index fa29dfe..7f6cc3c 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -185,8 +185,7 @@
 };
 
 static const struct pci_device_id qs_ata_pci_tbl[] = {
-	{ PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_2068_idx },
+	{ PCI_VDEVICE(PDC, 0x2068), board_2068_idx },
 
 	{ }	/* terminate list */
 };
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index c63dbab..3d9fa1c 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -123,13 +123,14 @@
 
 
 static const struct pci_device_id sil_pci_tbl[] = {
-	{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-	{ 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-	{ 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
-	{ 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
-	{ 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
-	{ 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
-	{ 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+	{ PCI_VDEVICE(CMD, 0x3112), sil_3112 },
+	{ PCI_VDEVICE(CMD, 0x0240), sil_3112 },
+	{ PCI_VDEVICE(CMD, 0x3512), sil_3512 },
+	{ PCI_VDEVICE(CMD, 0x3114), sil_3114 },
+	{ PCI_VDEVICE(ATI, 0x436e), sil_3112 },
+	{ PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq },
+	{ PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq },
+
 	{ }	/* terminate list */
 };
 
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 39cb07b..a951f40 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -344,11 +344,12 @@
 #endif
 
 static const struct pci_device_id sil24_pci_tbl[] = {
-	{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
-	{ 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
-	{ 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
-	{ 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
-	{ 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+	{ PCI_VDEVICE(CMD, 0x3124), BID_SIL3124 },
+	{ PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
+	{ PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
+	{ PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
+	{ PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
+
 	{ } /* terminate list */
 };
 
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 18d49ff..0738f52 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -67,13 +67,13 @@
 static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id sis_pci_tbl[] = {
-	{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
-	{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
-	{ PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ PCI_VDEVICE(SI, 0x180), sis_180 },
+	{ PCI_VDEVICE(SI, 0x181), sis_180 },
+	{ PCI_VDEVICE(SI, 0x182), sis_180 },
+
 	{ }	/* terminate list */
 };
 
-
 static struct pci_driver sis_pci_driver = {
 	.name			= DRV_NAME,
 	.id_table		= sis_pci_tbl,
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index d6d6658..84025a2 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -469,15 +469,15 @@
  * controller
  * */
 static const struct pci_device_id k2_sata_pci_tbl[] = {
-	{ 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
-	{ 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
-	{ 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
-	{ 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
-	{ 0x1166, 0x024b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+	{ PCI_VDEVICE(SERVERWORKS, 0x0240), 4 },
+	{ PCI_VDEVICE(SERVERWORKS, 0x0241), 4 },
+	{ PCI_VDEVICE(SERVERWORKS, 0x0242), 8 },
+	{ PCI_VDEVICE(SERVERWORKS, 0x024a), 4 },
+	{ PCI_VDEVICE(SERVERWORKS, 0x024b), 4 },
+
 	{ }
 };
 
-
 static struct pci_driver k2_sata_pci_driver = {
 	.name			= DRV_NAME,
 	.id_table		= k2_sata_pci_tbl,
@@ -485,19 +485,16 @@
 	.remove			= ata_pci_remove_one,
 };
 
-
 static int __init k2_sata_init(void)
 {
 	return pci_register_driver(&k2_sata_pci_driver);
 }
 
-
 static void __exit k2_sata_exit(void)
 {
 	pci_unregister_driver(&k2_sata_pci_driver);
 }
 
-
 MODULE_AUTHOR("Benjamin Herrenschmidt");
 MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
 MODULE_LICENSE("GPL");
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 091867e..8c74f2f 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -230,12 +230,11 @@
 };
 
 static const struct pci_device_id pdc_sata_pci_tbl[] = {
-	{ PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-	  board_20621 },
+	{ PCI_VDEVICE(PROMISE, 0x6622), board_20621 },
+
 	{ }	/* terminate list */
 };
 
-
 static struct pci_driver pdc_sata_pci_driver = {
 	.name			= DRV_NAME,
 	.id_table		= pdc_sata_pci_tbl,
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index dd76f37..5c603ca 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -61,13 +61,13 @@
 static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
 
 static const struct pci_device_id uli_pci_tbl[] = {
-	{ PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
-	{ PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
-	{ PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
+	{ PCI_VDEVICE(AL, 0x5289), uli_5289 },
+	{ PCI_VDEVICE(AL, 0x5287), uli_5287 },
+	{ PCI_VDEVICE(AL, 0x5281), uli_5281 },
+
 	{ }	/* terminate list */
 };
 
-
 static struct pci_driver uli_pci_driver = {
 	.name			= DRV_NAME,
 	.id_table		= uli_pci_tbl,
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index a72a238..f4455a1 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -77,9 +77,9 @@
 static void vt6420_error_handler(struct ata_port *ap);
 
 static const struct pci_device_id svia_pci_tbl[] = {
-	{ 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
-	{ 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
-	{ 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
+	{ PCI_VDEVICE(VIA, 0x0591), vt6420 },
+	{ PCI_VDEVICE(VIA, 0x3149), vt6420 },
+	{ PCI_VDEVICE(VIA, 0x3249), vt6421 },
 
 	{ }	/* terminate list */
 };
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index d0d92f3..273d88f 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -442,16 +442,15 @@
 	return rc;
 }
 
-
 static const struct pci_device_id vsc_sata_pci_tbl[] = {
 	{ PCI_VENDOR_ID_VITESSE, 0x7174,
 	  PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
 	{ PCI_VENDOR_ID_INTEL, 0x3200,
 	  PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+
 	{ }	/* terminate list */
 };
 
-
 static struct pci_driver vsc_sata_pci_driver = {
 	.name			= DRV_NAME,
 	.id_table		= vsc_sata_pci_tbl,
@@ -459,19 +458,16 @@
 	.remove			= ata_pci_remove_one,
 };
 
-
 static int __init vsc_sata_init(void)
 {
 	return pci_register_driver(&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");
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index 6cc93de..ac2c108 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -113,15 +113,13 @@
 
 	printk(KERN_ERR "adummy: version %s\n", DRV_VERSION);
 
-	adummy_dev = (struct adummy_dev *) kmalloc(sizeof(struct adummy_dev),
+	adummy_dev = kzalloc(sizeof(struct adummy_dev),
 						   GFP_KERNEL);
 	if (!adummy_dev) {
-		printk(KERN_ERR DEV_LABEL ": kmalloc() failed\n");
+		printk(KERN_ERR DEV_LABEL ": kzalloc() failed\n");
 		err = -ENOMEM;
 		goto out;
 	}
-	memset(adummy_dev, 0, sizeof(struct adummy_dev));
-
 	atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL);
 	if (!atm_dev) {
 		printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n");
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 4521a24..da599e6 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -915,8 +915,8 @@
 
 /********** make rate (not quite as much fun as Horizon) **********/
 
-static unsigned int make_rate (unsigned int rate, rounding r,
-			       u16 * bits, unsigned int * actual) {
+static int make_rate (unsigned int rate, rounding r,
+		      u16 * bits, unsigned int * actual) {
   unsigned char exp = -1; // hush gcc
   unsigned int man = -1;  // hush gcc
   
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 38fc054..5f25e5e 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1784,7 +1784,7 @@
 		write_fs (dev, RAM, (1 << (28 - FS155_VPI_BITS - FS155_VCI_BITS)) - 1);
 		dev->nchannels = FS155_NR_CHANNELS;
 	}
-	dev->atm_vccs = kmalloc (dev->nchannels * sizeof (struct atm_vcc *), 
+	dev->atm_vccs = kcalloc (dev->nchannels, sizeof (struct atm_vcc *),
 				 GFP_KERNEL);
 	fs_dprintk (FS_DEBUG_ALLOC, "Alloc atmvccs: %p(%Zd)\n",
 		    dev->atm_vccs, dev->nchannels * sizeof (struct atm_vcc *));
@@ -1794,9 +1794,8 @@
 		/* XXX Clean up..... */
 		return 1;
 	}
-	memset (dev->atm_vccs, 0, dev->nchannels * sizeof (struct atm_vcc *));
 
-	dev->tx_inuse = kmalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
+	dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
 	fs_dprintk (FS_DEBUG_ALLOC, "Alloc tx_inuse: %p(%d)\n", 
 		    dev->atm_vccs, dev->nchannels / 8);
 
@@ -1805,8 +1804,6 @@
 		/* XXX Clean up..... */
 		return 1;
 	}
-	memset (dev->tx_inuse, 0, dev->nchannels / 8);
-
 	/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
 	/* -- RAS2 : FS50 only: Default is OK. */
 
@@ -1893,14 +1890,11 @@
 	if (pci_enable_device(pci_dev)) 
 		goto err_out;
 
-	fs_dev = kmalloc (sizeof (struct fs_dev), GFP_KERNEL);
+	fs_dev = kzalloc (sizeof (struct fs_dev), GFP_KERNEL);
 	fs_dprintk (FS_DEBUG_ALLOC, "Alloc fs-dev: %p(%Zd)\n",
 		    fs_dev, sizeof (struct fs_dev));
 	if (!fs_dev)
 		goto err_out;
-
-	memset (fs_dev, 0, sizeof (struct fs_dev));
-  
 	atm_dev = atm_dev_register("fs", &ops, -1, NULL);
 	if (!atm_dev)
 		goto err_out_free_fs_dev;
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index f2511b4..b22a914 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -383,14 +383,12 @@
 	}
 	pci_set_drvdata(pci_dev, atm_dev);
 
-	he_dev = (struct he_dev *) kmalloc(sizeof(struct he_dev),
+	he_dev = kzalloc(sizeof(struct he_dev),
 							GFP_KERNEL);
 	if (!he_dev) {
 		err = -ENOMEM;
 		goto init_one_failure;
 	}
-	memset(he_dev, 0, sizeof(struct he_dev));
-
 	he_dev->pci_dev = pci_dev;
 	he_dev->atm_dev = atm_dev;
 	he_dev->atm_dev->dev_data = he_dev;
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index d1113e8..209dba1 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -2719,7 +2719,7 @@
 		goto out_disable;
 	}
 
-	dev = kmalloc(sizeof(hrz_dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(hrz_dev), GFP_KERNEL);
 	if (!dev) {
 		// perhaps we should be nice: deregister all adapters and abort?
 		PRINTD(DBG_ERR, "out of memory");
@@ -2727,8 +2727,6 @@
 		goto out_release;
 	}
 
-	memset(dev, 0, sizeof(hrz_dev));
-
 	pci_set_drvdata(pci_dev, dev);
 
 	// grab IRQ and install handler - move this someplace more sensible
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index b0369bb..7487f0a 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -642,11 +642,9 @@
 {
 	struct scq_info *scq;
 
-	scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL);
+	scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL);
 	if (!scq)
 		return NULL;
-	memset(scq, 0, sizeof(struct scq_info));
-
 	scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE,
 					 &scq->paddr);
 	if (scq->base == NULL) {
@@ -2142,11 +2140,9 @@
 {
 	struct rate_estimator *est;
 
-	est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL);
+	est = kzalloc(sizeof(struct rate_estimator), GFP_KERNEL);
 	if (!est)
 		return NULL;
-	memset(est, 0, sizeof(*est));
-
 	est->maxcps = pcr < 0 ? -pcr : pcr;
 	est->cps = est->maxcps;
 	est->avcps = est->cps << 5;
@@ -2451,14 +2447,12 @@
 
 	index = VPCI2VC(card, vpi, vci);
 	if (!card->vcs[index]) {
-		card->vcs[index] = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
+		card->vcs[index] = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
 		if (!card->vcs[index]) {
 			printk("%s: can't alloc vc in open()\n", card->name);
 			up(&card->mutex);
 			return -ENOMEM;
 		}
-		memset(card->vcs[index], 0, sizeof(struct vc_map));
-
 		card->vcs[index]->card = card;
 		card->vcs[index]->index = index;
 
@@ -2926,13 +2920,11 @@
 		for (vci = 3; vci < 5; vci++) {
 			index = VPCI2VC(card, vpi, vci);
 
-			vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
+			vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
 			if (!vc) {
 				printk("%s: can't alloc vc\n", card->name);
 				return -ENOMEM;
 			}
-			memset(vc, 0, sizeof(struct vc_map));
-
 			vc->index = index;
 			card->vcs[index] = vc;
 
@@ -2995,12 +2987,11 @@
 {
 	struct vc_map *vc;
 
-	vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
+	vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
 	if (!vc) {
 		printk("%s: can't alloc vc\n", card->name);
 		return -ENOMEM;
 	}
-	memset(vc, 0, sizeof(struct vc_map));
 	card->vcs[0] = vc;
 	vc->class = SCHED_UBR0;
 
@@ -3695,14 +3686,12 @@
 		goto err_out_disable_pdev;
 	}
 
-	card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
+	card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
 	if (!card) {
 		printk("idt77252-%d: can't allocate private data\n", index);
 		err = -ENOMEM;
 		goto err_out_disable_pdev;
 	}
-	memset(card, 0, sizeof(struct idt77252_dev));
-
 	card->revision = revision;
 	card->index = index;
 	card->pcidev = pcidev;
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index fe60a59..b9568e1 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -1482,16 +1482,10 @@
 static inline struct lanai_vcc *new_lanai_vcc(void)
 {
 	struct lanai_vcc *lvcc;
-	lvcc = (struct lanai_vcc *) kmalloc(sizeof(*lvcc), GFP_KERNEL);
+	lvcc =  kzalloc(sizeof(*lvcc), GFP_KERNEL);
 	if (likely(lvcc != NULL)) {
-		lvcc->vbase = NULL;
-		lvcc->rx.atmvcc = lvcc->tx.atmvcc = NULL;
-		lvcc->nref = 0;
-		memset(&lvcc->stats, 0, sizeof lvcc->stats);
-		lvcc->rx.buf.start = lvcc->tx.buf.start = NULL;
 		skb_queue_head_init(&lvcc->tx.backlog);
 #ifdef DEBUG
-		lvcc->tx.unqueue = NULL;
 		lvcc->vci = -1;
 #endif
 	}
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 2c65e82..083c5d3 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -603,9 +603,8 @@
 DPRINTK("start_rx\n");
 	zatm_dev = ZATM_DEV(dev);
 	size = sizeof(struct atm_vcc *)*zatm_dev->chans;
-	zatm_dev->rx_map = (struct atm_vcc **) kmalloc(size,GFP_KERNEL);
+	zatm_dev->rx_map =  kzalloc(size,GFP_KERNEL);
 	if (!zatm_dev->rx_map) return -ENOMEM;
-	memset(zatm_dev->rx_map,0,size);
 	/* set VPI/VCI split (use all VCIs and give what's left to VPIs) */
 	zpokel(zatm_dev,(1 << dev->ci_range.vci_bits)-1,uPD98401_VRR);
 	/* prepare free buffer pools */
@@ -801,6 +800,7 @@
 		i = m = 1;
 		zatm_dev->ubr_ref_cnt++;
 		zatm_dev->ubr = shaper;
+		*pcr = 0;
 	}
 	else {
 		if (min) {
@@ -951,9 +951,8 @@
 	skb_queue_head_init(&zatm_vcc->tx_queue);
 	init_waitqueue_head(&zatm_vcc->tx_wait);
 	/* initialize ring */
-	zatm_vcc->ring = kmalloc(RING_SIZE,GFP_KERNEL);
+	zatm_vcc->ring = kzalloc(RING_SIZE,GFP_KERNEL);
 	if (!zatm_vcc->ring) return -ENOMEM;
-	memset(zatm_vcc->ring,0,RING_SIZE);
 	loop = zatm_vcc->ring+RING_ENTRIES*RING_WORDS;
 	loop[0] = uPD98401_TXPD_V;
 	loop[1] = loop[2] = 0;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 99f87ef..36b88f6 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -20,7 +20,6 @@
  *
  */
 
-#include <linux/config.h>	/* CONFIG_PROC_FS */
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/types.h>
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 4abc193..ada68e6 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -19,7 +19,6 @@
  *    Questions/Comments/Bugfixes to iss_storagedev@hp.com
  *
  */
-#include <linux/config.h>	/* CONFIG_PROC_FS */
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/pci.h>
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index a6b2aa6..f2904f6 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -62,6 +62,8 @@
 
 #include <asm/uaccess.h>
 
+#define DRIVER_NAME	"pktcdvd"
+
 #if PACKET_DEBUG
 #define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
 #else
@@ -80,7 +82,7 @@
 
 static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
 static struct proc_dir_entry *pkt_proc;
-static int pkt_major;
+static int pktdev_major;
 static struct mutex ctl_mutex;	/* Serialize open/close/setup/teardown */
 static mempool_t *psd_pool;
 
@@ -89,7 +91,7 @@
 {
 	BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
 	if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
-		VPRINTK("pktcdvd: queue empty\n");
+		VPRINTK(DRIVER_NAME": queue empty\n");
 		atomic_set(&pd->iosched.attention, 1);
 		wake_up(&pd->wqueue);
 	}
@@ -400,7 +402,7 @@
 	int i;
 	struct request_sense *sense = cgc->sense;
 
-	printk("pktcdvd:");
+	printk(DRIVER_NAME":");
 	for (i = 0; i < CDROM_PACKET_SIZE; i++)
 		printk(" %02x", cgc->cmd[i]);
 	printk(" - ");
@@ -528,7 +530,7 @@
 				need_write_seek = 0;
 			if (need_write_seek && reads_queued) {
 				if (atomic_read(&pd->cdrw.pending_bios) > 0) {
-					VPRINTK("pktcdvd: write, waiting\n");
+					VPRINTK(DRIVER_NAME": write, waiting\n");
 					break;
 				}
 				pkt_flush_cache(pd);
@@ -537,7 +539,7 @@
 		} else {
 			if (!reads_queued && writes_queued) {
 				if (atomic_read(&pd->cdrw.pending_bios) > 0) {
-					VPRINTK("pktcdvd: read, waiting\n");
+					VPRINTK(DRIVER_NAME": read, waiting\n");
 					break;
 				}
 				pd->iosched.writing = 1;
@@ -600,7 +602,7 @@
 		set_bit(PACKET_MERGE_SEGS, &pd->flags);
 		return 0;
 	} else {
-		printk("pktcdvd: cdrom max_phys_segments too small\n");
+		printk(DRIVER_NAME": cdrom max_phys_segments too small\n");
 		return -EIO;
 	}
 }
@@ -1049,7 +1051,7 @@
 	for (f = 0; f < pkt->frames; f++)
 		if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
 			BUG();
-	VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt);
+	VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt);
 
 	atomic_set(&pkt->io_wait, 1);
 	pkt->w_bio->bi_rw = WRITE;
@@ -1286,7 +1288,7 @@
 
 static void pkt_print_settings(struct pktcdvd_device *pd)
 {
-	printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
+	printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
 	printk("%u blocks, ", pd->settings.size >> 2);
 	printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2');
 }
@@ -1471,7 +1473,7 @@
 		/*
 		 * paranoia
 		 */
-		printk("pktcdvd: write mode wrong %d\n", wp->data_block_type);
+		printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type);
 		return 1;
 	}
 	wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
@@ -1515,7 +1517,7 @@
 	if (ti->rt == 1 && ti->blank == 0)
 		return 1;
 
-	printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
+	printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
 	return 0;
 }
 
@@ -1533,7 +1535,7 @@
 		case 0x12: /* DVD-RAM */
 			return 1;
 		default:
-			VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
+			VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile);
 			return 0;
 	}
 
@@ -1542,22 +1544,22 @@
 	 * but i'm not sure, should we leave this to user apps? probably.
 	 */
 	if (di->disc_type == 0xff) {
-		printk("pktcdvd: Unknown disc. No track?\n");
+		printk(DRIVER_NAME": Unknown disc. No track?\n");
 		return 0;
 	}
 
 	if (di->disc_type != 0x20 && di->disc_type != 0) {
-		printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
+		printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type);
 		return 0;
 	}
 
 	if (di->erasable == 0) {
-		printk("pktcdvd: Disc not erasable\n");
+		printk(DRIVER_NAME": Disc not erasable\n");
 		return 0;
 	}
 
 	if (di->border_status == PACKET_SESSION_RESERVED) {
-		printk("pktcdvd: Can't write to last track (reserved)\n");
+		printk(DRIVER_NAME": Can't write to last track (reserved)\n");
 		return 0;
 	}
 
@@ -1593,12 +1595,12 @@
 
 	track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
 	if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
-		printk("pktcdvd: failed get_track\n");
+		printk(DRIVER_NAME": failed get_track\n");
 		return ret;
 	}
 
 	if (!pkt_writable_track(pd, &ti)) {
-		printk("pktcdvd: can't write to this track\n");
+		printk(DRIVER_NAME": can't write to this track\n");
 		return -EROFS;
 	}
 
@@ -1608,11 +1610,11 @@
 	 */
 	pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
 	if (pd->settings.size == 0) {
-		printk("pktcdvd: detected zero packet size!\n");
+		printk(DRIVER_NAME": detected zero packet size!\n");
 		return -ENXIO;
 	}
 	if (pd->settings.size > PACKET_MAX_SECTORS) {
-		printk("pktcdvd: packet size is too big\n");
+		printk(DRIVER_NAME": packet size is too big\n");
 		return -EROFS;
 	}
 	pd->settings.fp = ti.fp;
@@ -1654,7 +1656,7 @@
 			pd->settings.block_mode = PACKET_BLOCK_MODE2;
 			break;
 		default:
-			printk("pktcdvd: unknown data mode\n");
+			printk(DRIVER_NAME": unknown data mode\n");
 			return -EROFS;
 	}
 	return 0;
@@ -1688,10 +1690,10 @@
 	cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
 	ret = pkt_mode_select(pd, &cgc);
 	if (ret) {
-		printk("pktcdvd: write caching control failed\n");
+		printk(DRIVER_NAME": write caching control failed\n");
 		pkt_dump_sense(&cgc);
 	} else if (!ret && set)
-		printk("pktcdvd: enabled write caching on %s\n", pd->name);
+		printk(DRIVER_NAME": enabled write caching on %s\n", pd->name);
 	return ret;
 }
 
@@ -1805,11 +1807,11 @@
 	}
 
 	if (!buf[6] & 0x40) {
-		printk("pktcdvd: Disc type is not CD-RW\n");
+		printk(DRIVER_NAME": Disc type is not CD-RW\n");
 		return 1;
 	}
 	if (!buf[6] & 0x4) {
-		printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n");
+		printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
 		return 1;
 	}
 
@@ -1829,14 +1831,14 @@
 			*speed = us_clv_to_speed[sp];
 			break;
 		default:
-			printk("pktcdvd: Unknown disc sub-type %d\n",st);
+			printk(DRIVER_NAME": Unknown disc sub-type %d\n",st);
 			return 1;
 	}
 	if (*speed) {
-		printk("pktcdvd: Max. media speed: %d\n",*speed);
+		printk(DRIVER_NAME": Max. media speed: %d\n",*speed);
 		return 0;
 	} else {
-		printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st);
+		printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st);
 		return 1;
 	}
 }
@@ -1847,7 +1849,7 @@
 	struct request_sense sense;
 	int ret;
 
-	VPRINTK("pktcdvd: Performing OPC\n");
+	VPRINTK(DRIVER_NAME": Performing OPC\n");
 
 	init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
 	cgc.sense = &sense;
@@ -1865,12 +1867,12 @@
 	unsigned int write_speed, media_write_speed, read_speed;
 
 	if ((ret = pkt_probe_settings(pd))) {
-		VPRINTK("pktcdvd: %s failed probe\n", pd->name);
+		VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name);
 		return ret;
 	}
 
 	if ((ret = pkt_set_write_settings(pd))) {
-		DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name);
+		DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name);
 		return -EIO;
 	}
 
@@ -1882,26 +1884,26 @@
 		case 0x13: /* DVD-RW */
 		case 0x1a: /* DVD+RW */
 		case 0x12: /* DVD-RAM */
-			DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);
+			DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed);
 			break;
 		default:
 			if ((ret = pkt_media_speed(pd, &media_write_speed)))
 				media_write_speed = 16;
 			write_speed = min(write_speed, media_write_speed * 177);
-			DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176);
+			DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176);
 			break;
 	}
 	read_speed = write_speed;
 
 	if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
-		DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
+		DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name);
 		return -EIO;
 	}
 	pd->write_speed = write_speed;
 	pd->read_speed = read_speed;
 
 	if ((ret = pkt_perform_opc(pd))) {
-		DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name);
+		DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name);
 	}
 
 	return 0;
@@ -1929,7 +1931,7 @@
 		goto out_putdev;
 
 	if ((ret = pkt_get_last_written(pd, &lba))) {
-		printk("pktcdvd: pkt_get_last_written failed\n");
+		printk(DRIVER_NAME": pkt_get_last_written failed\n");
 		goto out_unclaim;
 	}
 
@@ -1959,11 +1961,11 @@
 
 	if (write) {
 		if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
-			printk("pktcdvd: not enough memory for buffers\n");
+			printk(DRIVER_NAME": not enough memory for buffers\n");
 			ret = -ENOMEM;
 			goto out_unclaim;
 		}
-		printk("pktcdvd: %lukB available on disc\n", lba << 1);
+		printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
 	}
 
 	return 0;
@@ -1983,7 +1985,7 @@
 static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
 {
 	if (flush && pkt_flush_cache(pd))
-		DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);
+		DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name);
 
 	pkt_lock_door(pd, 0);
 
@@ -2006,7 +2008,7 @@
 	struct pktcdvd_device *pd = NULL;
 	int ret;
 
-	VPRINTK("pktcdvd: entering open\n");
+	VPRINTK(DRIVER_NAME": entering open\n");
 
 	mutex_lock(&ctl_mutex);
 	pd = pkt_find_dev_from_minor(iminor(inode));
@@ -2040,7 +2042,7 @@
 out_dec:
 	pd->refcnt--;
 out:
-	VPRINTK("pktcdvd: failed open (%d)\n", ret);
+	VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
 	mutex_unlock(&ctl_mutex);
 	return ret;
 }
@@ -2088,7 +2090,7 @@
 
 	pd = q->queuedata;
 	if (!pd) {
-		printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
+		printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
 		goto end_io;
 	}
 
@@ -2110,13 +2112,13 @@
 	}
 
 	if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
-		printk("pktcdvd: WRITE for ro device %s (%llu)\n",
+		printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n",
 			pd->name, (unsigned long long)bio->bi_sector);
 		goto end_io;
 	}
 
 	if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
-		printk("pktcdvd: wrong bio size\n");
+		printk(DRIVER_NAME": wrong bio size\n");
 		goto end_io;
 	}
 
@@ -2319,7 +2321,7 @@
 	struct block_device *bdev;
 
 	if (pd->pkt_dev == dev) {
-		printk("pktcdvd: Recursive setup not allowed\n");
+		printk(DRIVER_NAME": Recursive setup not allowed\n");
 		return -EBUSY;
 	}
 	for (i = 0; i < MAX_WRITERS; i++) {
@@ -2327,11 +2329,11 @@
 		if (!pd2)
 			continue;
 		if (pd2->bdev->bd_dev == dev) {
-			printk("pktcdvd: %s already setup\n", bdevname(pd2->bdev, b));
+			printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b));
 			return -EBUSY;
 		}
 		if (pd2->pkt_dev == dev) {
-			printk("pktcdvd: Can't chain pktcdvd devices\n");
+			printk(DRIVER_NAME": Can't chain pktcdvd devices\n");
 			return -EBUSY;
 		}
 	}
@@ -2354,7 +2356,7 @@
 	atomic_set(&pd->cdrw.pending_bios, 0);
 	pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
 	if (IS_ERR(pd->cdrw.thread)) {
-		printk("pktcdvd: can't start kernel thread\n");
+		printk(DRIVER_NAME": can't start kernel thread\n");
 		ret = -ENOMEM;
 		goto out_mem;
 	}
@@ -2364,7 +2366,7 @@
 		proc->data = pd;
 		proc->proc_fops = &pkt_proc_fops;
 	}
-	DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
+	DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
 	return 0;
 
 out_mem:
@@ -2401,7 +2403,7 @@
 		return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
 
 	default:
-		VPRINTK("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
+		VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
 		return -ENOTTY;
 	}
 
@@ -2446,7 +2448,7 @@
 		if (!pkt_devs[idx])
 			break;
 	if (idx == MAX_WRITERS) {
-		printk("pktcdvd: max %d writers supported\n", MAX_WRITERS);
+		printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
 		return -EBUSY;
 	}
 
@@ -2470,15 +2472,15 @@
 
 	spin_lock_init(&pd->lock);
 	spin_lock_init(&pd->iosched.lock);
-	sprintf(pd->name, "pktcdvd%d", idx);
+	sprintf(pd->name, DRIVER_NAME"%d", idx);
 	init_waitqueue_head(&pd->wqueue);
 	pd->bio_queue = RB_ROOT;
 
-	disk->major = pkt_major;
+	disk->major = pktdev_major;
 	disk->first_minor = idx;
 	disk->fops = &pktcdvd_ops;
 	disk->flags = GENHD_FL_REMOVABLE;
-	sprintf(disk->disk_name, "pktcdvd%d", idx);
+	sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
 	disk->private_data = pd;
 	disk->queue = blk_alloc_queue(GFP_KERNEL);
 	if (!disk->queue)
@@ -2520,7 +2522,7 @@
 			break;
 	}
 	if (idx == MAX_WRITERS) {
-		DPRINTK("pktcdvd: dev not setup\n");
+		DPRINTK(DRIVER_NAME": dev not setup\n");
 		return -ENXIO;
 	}
 
@@ -2533,7 +2535,7 @@
 	blkdev_put(pd->bdev);
 
 	remove_proc_entry(pd->name, pkt_proc);
-	DPRINTK("pktcdvd: writer %s unmapped\n", pd->name);
+	DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name);
 
 	del_gendisk(pd->disk);
 	blk_cleanup_queue(pd->disk->queue);
@@ -2610,7 +2612,7 @@
 
 static struct miscdevice pkt_misc = {
 	.minor 		= MISC_DYNAMIC_MINOR,
-	.name  		= "pktcdvd",
+	.name  		= DRIVER_NAME,
 	.fops  		= &pkt_ctl_fops
 };
 
@@ -2623,28 +2625,28 @@
 	if (!psd_pool)
 		return -ENOMEM;
 
-	ret = register_blkdev(pkt_major, "pktcdvd");
+	ret = register_blkdev(pktdev_major, DRIVER_NAME);
 	if (ret < 0) {
-		printk("pktcdvd: Unable to register block device\n");
+		printk(DRIVER_NAME": Unable to register block device\n");
 		goto out2;
 	}
-	if (!pkt_major)
-		pkt_major = ret;
+	if (!pktdev_major)
+		pktdev_major = ret;
 
 	ret = misc_register(&pkt_misc);
 	if (ret) {
-		printk("pktcdvd: Unable to register misc device\n");
+		printk(DRIVER_NAME": Unable to register misc device\n");
 		goto out;
 	}
 
 	mutex_init(&ctl_mutex);
 
-	pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
+	pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
 
 	return 0;
 
 out:
-	unregister_blkdev(pkt_major, "pktcdvd");
+	unregister_blkdev(pktdev_major, DRIVER_NAME);
 out2:
 	mempool_destroy(psd_pool);
 	return ret;
@@ -2652,9 +2654,9 @@
 
 static void __exit pkt_exit(void)
 {
-	remove_proc_entry("pktcdvd", proc_root_driver);
+	remove_proc_entry(DRIVER_NAME, proc_root_driver);
 	misc_deregister(&pkt_misc);
-	unregister_blkdev(pkt_major, "pktcdvd");
+	unregister_blkdev(pktdev_major, DRIVER_NAME);
 	mempool_destroy(psd_pool);
 }
 
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index f2305ee..fdc8f89 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -636,7 +636,7 @@
 	intr = in_8(&sw->intr);
 	err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
 	if ((intr & ERROR_INTR) && fs->state != do_transfer)
-		printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n",
+		printk(KERN_ERR "swim3_interrupt, state=%d, dir=%x, intr=%x, err=%x\n",
 		       fs->state, rq_data_dir(fd_req), intr, err);
 	switch (fs->state) {
 	case locating:
@@ -742,7 +742,7 @@
 			if ((stat & ACTIVE) == 0 || resid != 0) {
 				/* musta been an error */
 				printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
-				printk(KERN_ERR "  state=%d, dir=%lx, intr=%x, err=%x\n",
+				printk(KERN_ERR "  state=%d, dir=%x, intr=%x, err=%x\n",
 				       fs->state, rq_data_dir(fd_req), intr, err);
 				end_request(fd_req, 0);
 				fs->state = idle;
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 22f8cf2..c603bf2 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -1,6 +1,6 @@
 config AGP
 	tristate "/dev/agpgart (AGP Support)"
-	depends on ALPHA || IA64 || PPC || X86
+	depends on ALPHA || IA64 || PARISC || PPC || X86
 	depends on PCI
 	---help---
 	  AGP (Accelerated Graphics Port) is a bus system mainly used to
@@ -122,6 +122,14 @@
 	  This option gives you AGP GART support for the HP ZX1 chipset
 	  for IA64 processors.
 
+config AGP_PARISC
+	tristate "HP Quicksilver AGP support"
+	depends on AGP && PARISC && 64BIT
+	help
+	  This option gives you AGP GART support for the HP Quicksilver
+	  AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000
+	  workstation...)
+
 config AGP_ALPHA_CORE
 	tristate "Alpha AGP support"
 	depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL)
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index d33a22f..3e58160 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -8,6 +8,7 @@
 obj-$(CONFIG_AGP_ALPHA_CORE)	+= alpha-agp.o
 obj-$(CONFIG_AGP_EFFICEON)	+= efficeon-agp.o
 obj-$(CONFIG_AGP_HP_ZX1)	+= hp-agp.o
+obj-$(CONFIG_AGP_PARISC)	+= parisc-agp.o
 obj-$(CONFIG_AGP_I460)		+= i460-agp.o
 obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o
 obj-$(CONFIG_AGP_NVIDIA)	+= nvidia-agp.o
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
new file mode 100644
index 0000000..17c50b0
--- /dev/null
+++ b/drivers/char/agp/parisc-agp.c
@@ -0,0 +1,416 @@
+/*
+ * HP Quicksilver AGP GART routines
+ *
+ * Copyright (c) 2006, Kyle McMartin <kyle@parisc-linux.org>
+ *
+ * Based on drivers/char/agpgart/hp-agp.c which is
+ * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
+ *	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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/klist.h>
+#include <linux/agp_backend.h>
+
+#include <asm-parisc/parisc-device.h>
+#include <asm-parisc/ropes.h>
+
+#include "agp.h"
+
+#define DRVNAME	"quicksilver"
+#define DRVPFX	DRVNAME ": "
+
+#ifndef log2
+#define log2(x)		ffz(~(x))
+#endif
+
+#define AGP8X_MODE_BIT		3
+#define AGP8X_MODE		(1 << AGP8X_MODE_BIT)
+
+static struct _parisc_agp_info {
+	void __iomem *ioc_regs;
+	void __iomem *lba_regs;
+
+	int lba_cap_offset;
+
+	u64 *gatt;
+	u64 gatt_entries;
+
+	u64 gart_base;
+	u64 gart_size;
+
+	int io_page_size;
+	int io_pages_per_kpage;
+} parisc_agp_info;
+
+static struct gatt_mask parisc_agp_masks[] =
+{
+        {
+		.mask = SBA_PDIR_VALID_BIT,
+		.type = 0
+	}
+};
+
+static struct aper_size_info_fixed parisc_agp_sizes[] =
+{
+        {0, 0, 0},              /* filled in by parisc_agp_fetch_size() */
+};
+
+static int
+parisc_agp_fetch_size(void)
+{
+	int size;
+
+	size = parisc_agp_info.gart_size / MB(1);
+	parisc_agp_sizes[0].size = size;
+	agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
+
+	return size;
+}
+
+static int
+parisc_agp_configure(void)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+
+	agp_bridge->gart_bus_addr = info->gart_base;
+	agp_bridge->capndx = info->lba_cap_offset;
+	agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
+
+	return 0;
+}
+
+static void
+parisc_agp_tlbflush(struct agp_memory *mem)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+
+	writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM);
+	readq(info->ioc_regs+IOC_PCOM);	/* flush */
+}
+
+static int
+parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+	int i;
+
+	for (i = 0; i < info->gatt_entries; i++) {
+		info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
+	}
+
+	return 0;
+}
+
+static int
+parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+
+	info->gatt[0] = SBA_AGPGART_COOKIE;
+
+	return 0;
+}
+
+static int
+parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+	int i, k;
+	off_t j, io_pg_start;
+	int io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = info->io_pages_per_kpage * pg_start;
+	io_pg_count = info->io_pages_per_kpage * mem->page_count;
+	if ((io_pg_start + io_pg_count) > info->gatt_entries) {
+		return -EINVAL;
+	}
+
+	j = io_pg_start;
+	while (j < (io_pg_start + io_pg_count)) {
+		if (info->gatt[j])
+			return -EBUSY;
+		j++;
+	}
+
+	if (mem->is_flushed == FALSE) {
+		global_cache_flush();
+		mem->is_flushed = TRUE;
+	}
+
+	for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+		unsigned long paddr;
+
+		paddr = mem->memory[i];
+		for (k = 0;
+		     k < info->io_pages_per_kpage;
+		     k++, j++, paddr += info->io_page_size) {
+			info->gatt[j] =
+				agp_bridge->driver->mask_memory(agp_bridge,
+					paddr, type);
+		}
+	}
+
+	agp_bridge->driver->tlb_flush(mem);
+
+	return 0;
+}
+
+static int
+parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+	int i, io_pg_start, io_pg_count;
+
+	if (type != 0 || mem->type != 0) {
+		return -EINVAL;
+	}
+
+	io_pg_start = info->io_pages_per_kpage * pg_start;
+	io_pg_count = info->io_pages_per_kpage * mem->page_count;
+	for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+		info->gatt[i] = agp_bridge->scratch_page;
+	}
+
+	agp_bridge->driver->tlb_flush(mem);
+	return 0;
+}
+
+static unsigned long
+parisc_agp_mask_memory(struct agp_bridge_data *bridge,
+		    unsigned long addr, int type)
+{
+	return SBA_PDIR_VALID_BIT | addr;
+}
+
+static void
+parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+	u32 command;
+
+	command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
+
+	command = agp_collect_device_status(bridge, mode, command);
+	command |= 0x00000100;
+
+	writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
+
+	agp_device_command(command, (mode & AGP8X_MODE) != 0);
+}
+
+struct agp_bridge_driver parisc_agp_driver = {
+	.owner			= THIS_MODULE,
+	.size_type		= FIXED_APER_SIZE,
+	.configure		= parisc_agp_configure,
+	.fetch_size		= parisc_agp_fetch_size,
+	.tlb_flush		= parisc_agp_tlbflush,
+	.mask_memory		= parisc_agp_mask_memory,
+	.masks			= parisc_agp_masks,
+	.agp_enable		= parisc_agp_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= parisc_agp_create_gatt_table,
+	.free_gatt_table	= parisc_agp_free_gatt_table,
+	.insert_memory		= parisc_agp_insert_memory,
+	.remove_memory		= parisc_agp_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,
+	.cant_use_aperture	= 1,
+};
+
+static int __init
+agp_ioc_init(void __iomem *ioc_regs)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+        u64 *iova_base, *io_pdir, io_tlb_ps;
+        int io_tlb_shift;
+
+        printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
+
+        info->ioc_regs = ioc_regs;
+
+        io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
+        switch (io_tlb_ps) {
+        case 0: io_tlb_shift = 12; break;
+        case 1: io_tlb_shift = 13; break;
+        case 2: io_tlb_shift = 14; break;
+        case 3: io_tlb_shift = 16; break;
+        default:
+                printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
+                       "configuration 0x%llx\n", io_tlb_ps);
+                info->gatt = NULL;
+                info->gatt_entries = 0;
+                return -ENODEV;
+        }
+        info->io_page_size = 1 << io_tlb_shift;
+        info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
+
+        iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
+        info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
+
+        info->gart_size = PLUTO_GART_SIZE;
+        info->gatt_entries = info->gart_size / info->io_page_size;
+
+        io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
+        info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
+
+        if (info->gatt[0] != SBA_AGPGART_COOKIE) {
+                info->gatt = NULL;
+                info->gatt_entries = 0;
+                printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
+                       "GART disabled\n");
+                return -ENODEV;
+        }
+
+        return 0;
+}
+
+static int
+lba_find_capability(int cap)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+        u16 status;
+        u8 pos, id;
+        int ttl = 48;
+
+        status = readw(info->lba_regs + PCI_STATUS);
+        if (!(status & PCI_STATUS_CAP_LIST))
+                return 0;
+        pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
+        while (ttl-- && pos >= 0x40) {
+                pos &= ~3;
+                id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
+                if (id == 0xff)
+                        break;
+                if (id == cap)
+                        return pos;
+                pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
+        }
+        return 0;
+}
+
+static int __init
+agp_lba_init(void __iomem *lba_hpa)
+{
+	struct _parisc_agp_info *info = &parisc_agp_info;
+        int cap;
+
+	info->lba_regs = lba_hpa;
+        info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
+
+        cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
+        if (cap != PCI_CAP_ID_AGP) {
+                printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
+                       cap, info->lba_cap_offset);
+                return -ENODEV;
+        }
+
+        return 0;
+}
+
+static int __init
+parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
+{
+	struct pci_dev *fake_bridge_dev = NULL;
+	struct agp_bridge_data *bridge;
+	int error = 0;
+
+	fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+	if (!fake_bridge_dev) {
+		error = -ENOMEM;
+		goto fail;
+	}
+
+	error = agp_ioc_init(ioc_hpa);
+	if (error)
+		goto fail;
+
+	error = agp_lba_init(lba_hpa);
+	if (error)
+		goto fail;
+
+	bridge = agp_alloc_bridge();
+	if (!bridge) {
+		error = -ENOMEM;
+		goto fail;
+	}
+	bridge->driver = &parisc_agp_driver;
+
+	fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
+	fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
+	bridge->dev = fake_bridge_dev;
+
+	error = agp_add_bridge(bridge);
+
+fail:
+	return error;
+}
+
+static struct device *next_device(struct klist_iter *i) {
+	struct klist_node * n = klist_next(i);
+	return n ? container_of(n, struct device, knode_parent) : NULL;
+}
+
+static int
+parisc_agp_init(void)
+{
+	extern struct sba_device *sba_list;
+
+	int err = -1;
+	struct parisc_device *sba = NULL, *lba = NULL;
+	struct lba_device *lbadev = NULL;
+	struct device *dev = NULL;
+	struct klist_iter i;
+
+	if (!sba_list)
+		goto out;
+
+	/* Find our parent Pluto */
+	sba = sba_list->dev;
+	if (!IS_PLUTO(sba)) {
+		printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
+		goto out;
+	}
+
+	/* Now search our Pluto for our precious AGP device... */
+	klist_iter_init(&sba->dev.klist_children, &i);
+	while ((dev = next_device(&i))) {
+		struct parisc_device *padev = to_parisc_device(dev);
+		if (IS_QUICKSILVER(padev))
+			lba = padev;
+	}
+	klist_iter_exit(&i);
+
+	if (!lba) {
+		printk(KERN_INFO DRVPFX "No AGP devices found.\n");
+		goto out;
+	}
+
+	lbadev = parisc_get_drvdata(lba);
+
+	/* w00t, let's go find our cookies... */
+	parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
+
+	return 0;
+
+out:
+	return err;
+}
+
+module_init(parisc_agp_init);
+
+MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index d0e92ed..486f97c 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -112,17 +112,6 @@
 
 #define NR_PORTS ARRAY_SIZE(rs_table)
 
-/*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-
 #include <asm/uaccess.h>
 
 #define serial_isroot()	(capable(CAP_SYS_ADMIN))
@@ -912,7 +901,7 @@
 	if (serial_paranoia_check(info, tty->name, "rs_write"))
 		return 0;
 
-	if (!info->xmit.buf || !tmp_buf)
+	if (!info->xmit.buf)
 		return 0;
 
 	local_save_flags(flags);
@@ -1778,7 +1767,6 @@
 {
 	struct async_struct	*info;
 	int 			retval, line;
-	unsigned long		page;
 
 	line = tty->index;
 	if ((line < 0) || (line >= NR_PORTS)) {
@@ -1798,17 +1786,6 @@
 #endif
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
-	if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
-		if (!page) {
-			return -ENOMEM;
-		}
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-	}
-
 	/*
 	 * If the port is the middle of closing, bail out now
 	 */
@@ -2090,11 +2067,6 @@
 	  kfree(info);
 	}
 
-	if (tmp_buf) {
-		free_page((unsigned long) tmp_buf);
-		tmp_buf = NULL;
-	}
-
 	release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
 }
 
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index b8c2225..9f8082f 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -11,7 +11,6 @@
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/timer.h>
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
 #include <linux/string.h>
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index f85b4eb..87b2fb5 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -748,18 +748,6 @@
 static int cy_next_channel; /* next minor available */
 
 /*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.  This buffer is
- * allocated when the first cy_open occurs.
- */
-static unsigned char *tmp_buf;
-
-/*
  * This is used to look up the divisor speeds and the timeouts
  * We're normally limited to 15 distinct baud rates.  The extra
  * are accessed via settings in info->flags.
@@ -2466,7 +2454,6 @@
 {
   struct cyclades_port  *info;
   int retval, line;
-  unsigned long page;
 
     line = tty->index;
     if ((line < 0) || (NR_PORTS <= line)){
@@ -2545,15 +2532,6 @@
     printk("cyc:cy_open (%d): incrementing count to %d\n",
         current->pid, info->count);
 #endif
-    if (!tmp_buf) {
-	page = get_zeroed_page(GFP_KERNEL);
-	if (!page)
-	    return -ENOMEM;
-	if (tmp_buf)
-	    free_page(page);
-	else
-	    tmp_buf = (unsigned char *) page;
-    }
 
     /*
      * If the port is the middle of closing, bail out now
@@ -2832,7 +2810,7 @@
         return 0;
     }
         
-    if (!info->xmit_buf || !tmp_buf)
+    if (!info->xmit_buf)
 	return 0;
 
     CY_LOCK(info, flags);
@@ -5490,10 +5468,6 @@
 #endif
         }
     }
-    if (tmp_buf) {
-	free_page((unsigned long) tmp_buf);
-	tmp_buf = NULL;
-    }
 } /* cy_cleanup_module */
 
 module_init(cy_init);
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 3baa2ab..c3f9558 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1113,11 +1113,8 @@
 		ch = card_ptr[crd];
 		for (count = 0; count < bd->numports; count++, ch++) 
 		{ /* Begin for each port */
-			if (ch) {
-				if (ch->tty)
-					tty_hangup(ch->tty);
-				kfree(ch->tmp_buf);
-			}
+			if (ch && ch->tty)
+				tty_hangup(ch->tty);
 		} /* End for each port */
 	} /* End for each card */
 	pci_unregister_driver (&epca_driver);
@@ -1635,16 +1632,6 @@
 		init_waitqueue_head(&ch->close_wait);
 
 		spin_unlock_irqrestore(&epca_lock, flags);
-
-		ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
-		if (!ch->tmp_buf) {
-			printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
-			release_region((int)bd->port, 4);
-			while(i-- > 0)
-				kfree((ch--)->tmp_buf);
-			return;
-		} else
-			memset((void *)ch->tmp_buf,0,ch->txbufsize);
 	} /* End for each port */
 
 	printk(KERN_INFO 
diff --git a/drivers/char/epca.h b/drivers/char/epca.h
index 456d6c8..a297238 100644
--- a/drivers/char/epca.h
+++ b/drivers/char/epca.h
@@ -130,7 +130,6 @@
 	unsigned long  c_oflag;
 	unsigned char __iomem *txptr;
 	unsigned char __iomem *rxptr;
-	unsigned char *tmp_buf;
 	struct board_info           *board;
 	struct board_chan	    __iomem *brdchan;
 	struct digi_struct          digiext;
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index 65c9d2e..2165324 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -26,7 +26,6 @@
  *      Linux.
  */
 
-#include <linux/config.h> /* for CONFIG_FT_* */
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/ioport.h>
diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c
index a61ef50..dab6346 100644
--- a/drivers/char/ftape/zftape/zftape-rw.c
+++ b/drivers/char/ftape/zftape/zftape-rw.c
@@ -24,7 +24,6 @@
  *      zftape.
  */
 
-#include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */
 #include <linux/errno.h>
 #include <linux/mm.h>
 
diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h
index 14c07f0..1ceec22 100644
--- a/drivers/char/ftape/zftape/zftape-rw.h
+++ b/drivers/char/ftape/zftape/zftape-rw.h
@@ -28,7 +28,6 @@
  *
  */
 
-#include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */
 #include "../zftape/zftape-buffers.h"
 
 #define SEGMENTS_PER_TAPE  (ft_segments_per_track * ft_tracks_per_tape)
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 4711d9b..87127e4 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -33,8 +33,6 @@
 
 #define DEBUG 
 
-static char *                  tmp_buf; 
-
 static int gs_debug;
 
 #ifdef DEBUG
@@ -205,7 +203,7 @@
 	if (!tty) return -EIO;
 
 	port = tty->driver_data;
-	if (!port || !port->xmit_buf || !tmp_buf)
+	if (!port || !port->xmit_buf)
 		return -EIO;
 
 	local_save_flags(flags);
@@ -837,24 +835,9 @@
 int gs_init_port(struct gs_port *port)
 {
 	unsigned long flags;
-	unsigned long page;
 
 	func_enter ();
 
-        if (!tmp_buf) {
-		page = get_zeroed_page(GFP_KERNEL);
-		spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */
-		if (tmp_buf)
-			free_page(page);
-		else
-			tmp_buf = (unsigned char *) page;
-		spin_unlock_irqrestore (&port->driver_lock, flags);
-		if (!tmp_buf) {
-			func_exit ();
-			return -ENOMEM;
-		}
-	}
-
 	if (port->flags & ASYNC_INITIALIZED) {
 		func_exit ();
 		return 0;
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index 8b6f197..f144a94 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -29,6 +29,7 @@
 #include <asm/hvconsole.h>
 #include <asm/vio.h>
 #include <asm/prom.h>
+#include <asm/firmware.h>
 #include <asm/iseries/vio.h>
 #include <asm/iseries/hv_call.h>
 #include <asm/iseries/hv_lp_config.h>
@@ -488,6 +489,9 @@
 	atomic_t wait_flag;
 	int rc;
 
+	if (!firmware_has_feature(FW_FEATURE_ISERIES))
+		return -EIO;
+
 	/* +2 for fudge */
 	rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
 			viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
@@ -562,7 +566,7 @@
 
 	for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
 			vty = of_find_node_by_name(vty, "vty")) {
-		uint32_t *vtermno;
+		const uint32_t *vtermno;
 
 		/* We have statically defined space for only a certain number
 		 * of console adapters.
@@ -571,7 +575,7 @@
 				(num_found >= VTTY_PORTS))
 			break;
 
-		vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+		vtermno = get_property(vty, "reg", NULL);
 		if (!vtermno)
 			continue;
 
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index cc95941..f9c0084 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -35,6 +35,7 @@
 #include <asm/hvconsole.h>
 #include <asm/vio.h>
 #include <asm/prom.h>
+#include <asm/firmware.h>
 
 #include "hvc_console.h"
 
@@ -120,6 +121,9 @@
 {
 	int rc;
 
+	if (firmware_has_feature(FW_FEATURE_ISERIES))
+		return -EIO;
+
 	/* Register as a vio device to receive callbacks */
 	rc = vio_register_driver(&hvc_vio_driver);
 
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
index 3cf4d64..c9caff5 100644
--- a/drivers/char/hw_random/ixp4xx-rng.c
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -15,7 +15,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index 5426b1e..5c0dec3 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -30,7 +30,6 @@
  * processor from ever speculating a cache line from this page.
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
index 7719bd7..4d47d79 100644
--- a/drivers/char/nsc_gpio.c
+++ b/drivers/char/nsc_gpio.c
@@ -7,7 +7,6 @@
    Copyright (c) 2005      Jim Cromie <jim.cromie@gmail.com>
 */
 
-#include <linux/config.h>
 #include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/errno.h>
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index d1ecb2c..73e3242 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -35,7 +35,6 @@
 
 #define MAX_DEVICE_COUNT 4
 
-#include <linux/config.h>	
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 214d8501..b0ab3f2 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -81,7 +81,6 @@
 
 static struct riscom_board * IRQ_to_board[16];
 static struct tty_driver *riscom_driver;
-static unsigned char * tmp_buf;
 
 static unsigned long baud_table[] =  {
 	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
@@ -1124,7 +1123,7 @@
 	
 	bp = port_Board(port);
 
-	if (!tty || !port->xmit_buf || !tmp_buf)
+	if (!tty || !port->xmit_buf)
 		return 0;
 
 	save_flags(flags);
@@ -1612,11 +1611,6 @@
 	if (!riscom_driver)	
 		return -ENOMEM;
 	
-	if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
-		printk(KERN_ERR "rc: Couldn't get free page.\n");
-		put_tty_driver(riscom_driver);
-		return 1;
-	}
 	memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
 	riscom_driver->owner = THIS_MODULE;
 	riscom_driver->name = "ttyL";
@@ -1629,7 +1623,6 @@
 	riscom_driver->flags = TTY_DRIVER_REAL_RAW;
 	tty_set_operations(riscom_driver, &riscom_ops);
 	if ((error = tty_register_driver(riscom_driver)))  {
-		free_page((unsigned long)tmp_buf);
 		put_tty_driver(riscom_driver);
 		printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
 				"error = %d\n",
@@ -1657,7 +1650,6 @@
 
 	save_flags(flags);
 	cli();
-	free_page((unsigned long)tmp_buf);
 	tty_unregister_driver(riscom_driver);
 	put_tty_driver(riscom_driver);
 	restore_flags(flags);
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index b4ea126..f4809c8 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -119,17 +119,6 @@
 #define NR_PORTS        ARRAY_SIZE(cy_port)
 
 /*
- * tmp_buf is used as a temporary buffer by serial_write.  We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf = 0;
-
-/*
  * This is used to look up the divisor speeds and the timeouts
  * We're normally limited to 15 distinct baud rates.  The extra
  * are accessed via settings in info->flags.
@@ -1132,7 +1121,7 @@
     if (serial_paranoia_check(info, tty->name, "cy_put_char"))
 	return;
 
-    if (!tty || !info->xmit_buf)
+    if (!info->xmit_buf)
 	return;
 
     local_irq_save(flags);
@@ -1198,7 +1187,7 @@
 	return 0;
     }
 	
-    if (!tty || !info->xmit_buf || !tmp_buf){
+    if (!info->xmit_buf){
         return 0;
     }
 
@@ -1983,13 +1972,6 @@
     tty->driver_data = info;
     info->tty = tty;
 
-    if (!tmp_buf) {
-	tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
-	if (!tmp_buf){
-	    return -ENOMEM;
-        }
-    }
-
     /*
      * Start up serial port
      */
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 57e31e5..8fd71a5 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -203,9 +203,7 @@
 #define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $"
 #define RCS_REV "$Revision: 1.33 $"
 
-
 #include <linux/module.h>
-#include <linux/config.h> 
 #include <linux/kdev_t.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 38d9498..a4150c4 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -63,7 +63,6 @@
 #define MAX_PCI_DEVICES 10
 #define MAX_TOTAL_DEVICES 20
 
-#include <linux/config.h>	
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
index 8f89948..aaac94db 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -49,7 +49,6 @@
 #define PFX		DRV_NAME ": "
 
 /* Includes */
-#include <linux/config.h>		/* For CONFIG_WATCHDOG_NOWAYOUT/... */
 #include <linux/module.h>		/* For module specific items */
 #include <linux/moduleparam.h>		/* For new moduleparam's */
 #include <linux/types.h>		/* For standard types (like size_t) */
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index 8f90b90..5dbd7dc 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -27,7 +27,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index 6f8515d..8e1e6e4 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -49,7 +49,6 @@
  *	More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
  */
 
-#include <linux/config.h>	/* For CONFIG_WATCHDOG_NOWAYOUT/... */
 #include <linux/module.h>	/* For module specific items */
 #include <linux/moduleparam.h>	/* For new moduleparam's */
 #include <linux/types.h>	/* For standard types (like size_t) */
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index 2de6e49..f4872c8 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -31,7 +31,6 @@
  *	Includes, defines, variables, module parameters, ...
  */
 
-#include <linux/config.h>	/* For CONFIG_WATCHDOG_NOWAYOUT/... */
 #include <linux/module.h>	/* For module specific items */
 #include <linux/moduleparam.h>	/* For new moduleparam's */
 #include <linux/types.h>	/* For standard types (like size_t) */
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c
index db2731b..3a55fc6 100644
--- a/drivers/char/watchdog/pnx4008_wdt.c
+++ b/drivers/char/watchdog/pnx4008_wdt.c
@@ -14,7 +14,6 @@
  * or implied.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
index d418b82..22915cc 100644
--- a/drivers/clocksource/scx200_hrt.c
+++ b/drivers/clocksource/scx200_hrt.c
@@ -63,7 +63,7 @@
 
 static int __init init_hrt_clocksource(void)
 {
-	/* Make sure scx200 has initializedd the configuration block */
+	/* Make sure scx200 has initialized the configuration block */
 	if (!scx200_cb_present())
 		return -ENODEV;
 
@@ -76,7 +76,7 @@
 	}
 
 	/* write timer config */
-	outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0,
+	outb(HR_TMEN | (mhz27 ? HR_TMCLKSEL : 0),
 	     scx200_cb_base + SCx200_TMCNFG_OFFSET);
 
 	if (mhz27) {
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 2caaf71..86e69b7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -52,8 +52,14 @@
  * The mutex locks both lists.
  */
 static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
-static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list);
+static struct srcu_notifier_head cpufreq_transition_notifier_list;
 
+static int __init init_cpufreq_transition_notifier_list(void)
+{
+	srcu_init_notifier_head(&cpufreq_transition_notifier_list);
+	return 0;
+}
+core_initcall(init_cpufreq_transition_notifier_list);
 
 static LIST_HEAD(cpufreq_governor_list);
 static DEFINE_MUTEX (cpufreq_governor_mutex);
@@ -262,14 +268,14 @@
 				freqs->old = policy->cur;
 			}
 		}
-		blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+		srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
 				CPUFREQ_PRECHANGE, freqs);
 		adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
 		break;
 
 	case CPUFREQ_POSTCHANGE:
 		adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
-		blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+		srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
 				CPUFREQ_POSTCHANGE, freqs);
 		if (likely(policy) && likely(policy->cpu == freqs->cpu))
 			policy->cur = freqs->new;
@@ -1049,7 +1055,7 @@
 		freqs.old = cpu_policy->cur;
 		freqs.new = cur_freq;
 
-		blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+		srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
 				    CPUFREQ_SUSPENDCHANGE, &freqs);
 		adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
 
@@ -1130,7 +1136,7 @@
 			freqs.old = cpu_policy->cur;
 			freqs.new = cur_freq;
 
-			blocking_notifier_call_chain(
+			srcu_notifier_call_chain(
 					&cpufreq_transition_notifier_list,
 					CPUFREQ_RESUMECHANGE, &freqs);
 			adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
@@ -1176,7 +1182,7 @@
 
 	switch (list) {
 	case CPUFREQ_TRANSITION_NOTIFIER:
-		ret = blocking_notifier_chain_register(
+		ret = srcu_notifier_chain_register(
 				&cpufreq_transition_notifier_list, nb);
 		break;
 	case CPUFREQ_POLICY_NOTIFIER:
@@ -1208,7 +1214,7 @@
 
 	switch (list) {
 	case CPUFREQ_TRANSITION_NOTIFIER:
-		ret = blocking_notifier_chain_unregister(
+		ret = srcu_notifier_chain_unregister(
 				&cpufreq_transition_notifier_list, nb);
 		break;
 	case CPUFREQ_POLICY_NOTIFIER:
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index d965d07..371ed4f 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -32,7 +32,6 @@
     The w83791g chip is the same as the w83791d but lead-free.
 */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 952a28d..3e276e9 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -9,7 +9,6 @@
  * kind, whether express or implied.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 0cb7b9b..965c436 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -23,7 +23,6 @@
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
index 68c74bb..c1cec23 100644
--- a/drivers/ide/pci/jmicron.c
+++ b/drivers/ide/pci/jmicron.c
@@ -5,7 +5,6 @@
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/pci.h>
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index 608cd76..5f6950c 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -17,7 +17,6 @@
 
 #undef REALLY_SLOW_IO		/* most systems can safely undef this */
 
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c
index 11b7378..a82157d 100644
--- a/drivers/infiniband/hw/ipath/ipath_mmap.c
+++ b/drivers/infiniband/hw/ipath/ipath_mmap.c
@@ -30,7 +30,6 @@
  * SOFTWARE.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/mm.h>
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 489022b..0945336 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -13,7 +13,6 @@
  *
  */
 
-
 #include <linux/init.h>
 #include "hisax.h"
 #include "isac.h"
@@ -45,33 +44,31 @@
 #define PCI_IRQ_DISABLE		0xff0000
 #define PCI_IRQ_ASSERT		0x800000
 
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
+static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off)
 {
 	register u_char ret;
 
 	byteout(ale, off);
 	ret = bytein(adr);
-	return (ret);
+	return ret;
 }
 
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+static inline void readfifo(unsigned int ale, unsigned int adr, u_char off,
+		u_char *data, int size)
 {
 	byteout(ale, off);
 	insb(adr, data, size);
 }
 
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+static inline void writereg(unsigned int ale, unsigned int adr, u_char off,
+		u_char data)
 {
 	byteout(ale, off);
 	byteout(adr, data);
 }
 
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+static inline void writefifo(unsigned int ale, unsigned int adr, u_char off,
+		u_char *data, int size)
 {
 	byteout(ale, off);
 	outsb(adr, data, size);
@@ -79,39 +76,34 @@
 
 /* Interface functions */
 
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
+static u_char ReadISAC(struct IsdnCardState *cs, u_char offset)
 {
-	return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
+	return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset);
 }
 
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
 {
 	writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
 }
 
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+static void ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
 }
 
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+static void WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
 {
 	writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
 }
 
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
 {
-	return (readreg(cs->hw.niccy.hscx_ale,
-			cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
+	return readreg(cs->hw.niccy.hscx_ale,
+			cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0));
 }
 
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset,
+		u_char value)
 {
 	writereg(cs->hw.niccy.hscx_ale,
 		 cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
@@ -130,8 +122,8 @@
 
 #include "hscx_irq.c"
 
-static irqreturn_t
-niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t niccy_interrupt(int intno, void *dev_id,
+		struct pt_regs *regs)
 {
 	struct IsdnCardState *cs = dev_id;
 	u_char val;
@@ -141,21 +133,23 @@
 	if (cs->subtyp == NICCY_PCI) {
 		int ival;
 		ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
-		if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
+		if (!(ival & PCI_IRQ_ASSERT)) {	/* IRQ not for us (shared) */
 			spin_unlock_irqrestore(&cs->lock, flags);
 			return IRQ_NONE;
 		}
 		outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
 	}
-	val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
-      Start_HSCX:
+	val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
+			HSCX_ISTA + 0x40);
+Start_HSCX:
 	if (val)
 		hscx_int_main(cs, val);
 	val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
-      Start_ISAC:
+Start_ISAC:
 	if (val)
 		isac_interrupt(cs, val);
-	val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+	val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
+			HSCX_ISTA + 0x40);
 	if (val) {
 		if (cs->debug & L1_DEB_HSCX)
 			debugl1(cs, "HSCX IntStat after IntRoutine");
@@ -168,21 +162,21 @@
 		goto Start_ISAC;
 	}
 	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
-	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
+	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,
+		 0xFF);
 	writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
 	writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
 	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
-	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
+	writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,0);
 	spin_unlock_irqrestore(&cs->lock, flags);
 	return IRQ_HANDLED;
 }
 
-static void
-release_io_niccy(struct IsdnCardState *cs)
+static void release_io_niccy(struct IsdnCardState *cs)
 {
 	if (cs->subtyp == NICCY_PCI) {
 		int val;
-		
+
 		val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
 		val &= PCI_IRQ_DISABLE;
 		outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
@@ -194,8 +188,7 @@
 	}
 }
 
-static void
-niccy_reset(struct IsdnCardState *cs)
+static void niccy_reset(struct IsdnCardState *cs)
 {
 	if (cs->subtyp == NICCY_PCI) {
 		int val;
@@ -207,29 +200,28 @@
 	inithscxisac(cs, 3);
 }
 
-static int
-niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
 {
 	u_long flags;
 
 	switch (mt) {
-		case CARD_RESET:
-			spin_lock_irqsave(&cs->lock, flags);
-			niccy_reset(cs);
-			spin_unlock_irqrestore(&cs->lock, flags);
-			return(0);
-		case CARD_RELEASE:
-			release_io_niccy(cs);
-			return(0);
-		case CARD_INIT:
-			spin_lock_irqsave(&cs->lock, flags);
-			niccy_reset(cs);
-			spin_unlock_irqrestore(&cs->lock, flags);
-			return(0);
-		case CARD_TEST:
-			return(0);
+	case CARD_RESET:
+		spin_lock_irqsave(&cs->lock, flags);
+		niccy_reset(cs);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return 0;
+	case CARD_RELEASE:
+		release_io_niccy(cs);
+		return 0;
+	case CARD_INIT:
+		spin_lock_irqsave(&cs->lock, flags);
+		niccy_reset(cs);
+		spin_unlock_irqrestore(&cs->lock, flags);
+		return 0;
+	case CARD_TEST:
+		return 0;
 	}
-	return(0);
+	return 0;
 }
 
 static struct pci_dev *niccy_dev __devinitdata = NULL;
@@ -237,8 +229,7 @@
 static struct pnp_card *pnp_c __devinitdata = NULL;
 #endif
 
-int __devinit
-setup_niccy(struct IsdnCard *card)
+int __devinit setup_niccy(struct IsdnCard *card)
 {
 	struct IsdnCardState *cs = card->cs;
 	char tmp[64];
@@ -246,40 +237,44 @@
 	strcpy(tmp, niccy_revision);
 	printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
 	if (cs->typ != ISDN_CTYPE_NICCY)
-		return (0);
+		return 0;
 #ifdef __ISAPNP__
 	if (!card->para[1] && isapnp_present()) {
 		struct pnp_dev *pnp_d = NULL;
 		int err;
 
-		if ((pnp_c = pnp_find_card(
-			ISAPNP_VENDOR('S', 'D', 'A'),
-			ISAPNP_FUNCTION(0x0150), pnp_c))) {
-			if (!(pnp_d = pnp_find_dev(pnp_c,
-				ISAPNP_VENDOR('S', 'D', 'A'),
-				ISAPNP_FUNCTION(0x0150), pnp_d))) {
-				printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
-				return (0);
+		pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'),
+				ISAPNP_FUNCTION(0x0150), pnp_c);
+		if (pnp_c) {
+			pnp_d = pnp_find_dev(pnp_c,
+					ISAPNP_VENDOR('S', 'D', 'A'),
+					ISAPNP_FUNCTION(0x0150), pnp_d);
+			if (!pnp_d) {
+				printk(KERN_ERR "NiccyPnP: PnP error card "
+					"found, no device\n");
+				return 0;
 			}
 			pnp_disable_dev(pnp_d);
 			err = pnp_activate_dev(pnp_d);
-			if (err<0) {
-				printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
-					__FUNCTION__, err);
-				return(0);
+			if (err < 0) {
+				printk(KERN_WARNING "%s: pnp_activate_dev "
+					"ret(%d)\n", __FUNCTION__, err);
+				return 0;
 			}
 			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);
-			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]);
+			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]);
 				pnp_disable_dev(pnp_d);
-				return(0);
+				return 0;
 			}
-		} else {
+		} else
 			printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
-		}
 	}
 #endif
 	if (card->para[1]) {
@@ -291,50 +286,51 @@
 		cs->subtyp = NICCY_PNP;
 		cs->irq = card->para[0];
 		if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
-			printk(KERN_WARNING
-				"HiSax: %s data port %x-%x already in use\n",
-				CardType[card->typ],
-				cs->hw.niccy.isac,
-				cs->hw.niccy.isac + 1);
-			return (0);
+			printk(KERN_WARNING "HiSax: %s data port %x-%x "
+				"already in use\n", CardType[card->typ],
+				cs->hw.niccy.isac, cs->hw.niccy.isac + 1);
+			return 0;
 		}
 		if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
-			printk(KERN_WARNING
-				"HiSax: %s address port %x-%x already in use\n",
-				CardType[card->typ],
+			printk(KERN_WARNING "HiSax: %s address port %x-%x "
+				"already in use\n", CardType[card->typ],
 				cs->hw.niccy.isac_ale,
 				cs->hw.niccy.isac_ale + 1);
 			release_region(cs->hw.niccy.isac, 2);
-			return (0);
+			return 0;
 		}
 	} else {
 #ifdef CONFIG_PCI
 		u_int pci_ioaddr;
 		cs->subtyp = 0;
 		if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
-			PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
+						 PCI_DEVICE_ID_SATSAGEM_NICCY,
+						 niccy_dev))) {
 			if (pci_enable_device(niccy_dev))
-				return(0);
+				return 0;
 			/* get IRQ */
 			if (!niccy_dev->irq) {
-				printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
-				return(0);
+				printk(KERN_WARNING
+				       "Niccy: No IRQ for PCI card found\n");
+				return 0;
 			}
 			cs->irq = niccy_dev->irq;
 			cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
 			if (!cs->hw.niccy.cfg_reg) {
-				printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
-				return(0);
+				printk(KERN_WARNING
+				       "Niccy: No IO-Adr for PCI cfg found\n");
+				return 0;
 			}
 			pci_ioaddr = pci_resource_start(niccy_dev, 1);
 			if (!pci_ioaddr) {
-				printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
-				return(0);
+				printk(KERN_WARNING
+				       "Niccy: No IO-Adr for PCI card found\n");
+				return 0;
 			}
 			cs->subtyp = NICCY_PCI;
 		} else {
 			printk(KERN_WARNING "Niccy: No PCI card found\n");
-			return(0);
+			return 0;
 		}
 		cs->irq_flags |= IRQF_SHARED;
 		cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
@@ -343,29 +339,28 @@
 		cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
 		if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
 			printk(KERN_WARNING
-				"HiSax: %s data port %x-%x already in use\n",
-				CardType[card->typ],
-				cs->hw.niccy.isac,
-				cs->hw.niccy.isac + 4);
-			return (0);
+			       "HiSax: %s data port %x-%x already in use\n",
+			       CardType[card->typ],
+			       cs->hw.niccy.isac, cs->hw.niccy.isac + 4);
+			return 0;
 		}
 		if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
 			printk(KERN_WARNING
 			       "HiSax: %s pci port %x-%x already in use\n",
-				CardType[card->typ],
-				cs->hw.niccy.cfg_reg,
-				cs->hw.niccy.cfg_reg + 0x40);
+			       CardType[card->typ],
+			       cs->hw.niccy.cfg_reg,
+			       cs->hw.niccy.cfg_reg + 0x40);
 			release_region(cs->hw.niccy.isac, 4);
-			return (0);
+			return 0;
 		}
 #else
 		printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
 		printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
-		return (0);
-#endif /* CONFIG_PCI */
+		return 0;
+#endif				/* CONFIG_PCI */
 	}
 	printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
-		CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
+		CardType[cs->typ], (cs->subtyp == 1) ? "PnP" : "PCI",
 		cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
 	setup_isac(cs);
 	cs->readisac = &ReadISAC;
@@ -379,10 +374,10 @@
 	cs->irq_func = &niccy_interrupt;
 	ISACVersion(cs, "Niccy:");
 	if (HscxVersion(cs, "Niccy:")) {
-		printk(KERN_WARNING
-		    "Niccy: wrong HSCX versions check IO address\n");
+		printk(KERN_WARNING "Niccy: wrong HSCX versions check IO "
+			"address\n");
 		release_io_niccy(cs);
-		return (0);
+		return 0;
 	}
-	return (1);
+	return 1;
 }
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
index e9f0611..599878c 100644
--- a/drivers/leds/leds-ams-delta.c
+++ b/drivers/leds/leds-ams-delta.c
@@ -8,7 +8,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7fc692a..3df0e7a 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -18,7 +18,7 @@
 	  service processor board as a regular serial port. To make use of
 	  this feature serial driver support (CONFIG_SERIAL_8250) must be
 	  enabled.
-	  
+
 	  WARNING: This software may not be supported or function
 	  correctly on your IBM server. Please consult the IBM ServerProven
 	  website <http://www.pc.ibm.com/ww/eserver/xseries/serverproven> for
@@ -28,5 +28,33 @@
 
 	  If unsure, say N.
 
-endmenu
+config TIFM_CORE
+	tristate "TI Flash Media interface support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL
+	help
+	  If you want support for Texas Instruments(R) Flash Media adapters
+	  you should select this option and then also choose an appropriate
+	  host adapter, such as 'TI Flash Media PCI74xx/PCI76xx host adapter
+	  support', if you have a TI PCI74xx compatible card reader, for
+	  example.
+	  You will also have to select some flash card format drivers. MMC/SD
+	  cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD
+	  Interface support (MMC_TIFM_SD)'.
 
+          To compile this driver as a module, choose M here: the module will
+	  be called tifm_core.
+
+config TIFM_7XX1
+	tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)"
+	depends on PCI && TIFM_CORE && EXPERIMENTAL
+	default TIFM_CORE
+	help
+	  This option enables support for Texas Instruments(R) PCI74xx and
+	  PCI76xx families of Flash Media adapters, found in many laptops.
+	  To make actual use of the device, you will have to select some
+	  flash card format drivers, as outlined in the TIFM_CORE Help.
+
+          To compile this driver as a module, choose M here: the module will
+	  be called tifm_7xx1.
+
+endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c1bf1fb..d65ece7 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -6,3 +6,5 @@
 obj-$(CONFIG_IBM_ASM)		+= ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)	+= hdpuftrs/
 obj-$(CONFIG_LKDTM)		+= lkdtm.o
+obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
+obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
new file mode 100644
index 0000000..a7ed304
--- /dev/null
+++ b/drivers/misc/tifm_7xx1.c
@@ -0,0 +1,437 @@
+/*
+ *  tifm_7xx1.c - TI FlashMedia driver
+ *
+ *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/tifm.h>
+#include <linux/dma-mapping.h>
+
+#define DRIVER_NAME "tifm_7xx1"
+#define DRIVER_VERSION "0.6"
+
+static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
+{
+	int cnt;
+	unsigned long flags;
+
+	spin_lock_irqsave(&fm->lock, flags);
+	if (!fm->inhibit_new_cards) {
+		for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+			if (fm->sockets[cnt] == sock) {
+				fm->remove_mask |= (1 << cnt);
+				queue_work(fm->wq, &fm->media_remover);
+				break;
+			}
+		}
+	}
+	spin_unlock_irqrestore(&fm->lock, flags);
+}
+
+static void tifm_7xx1_remove_media(void *adapter)
+{
+	struct tifm_adapter *fm = adapter;
+	unsigned long flags;
+	int cnt;
+	struct tifm_dev *sock;
+
+	if (!class_device_get(&fm->cdev))
+		return;
+	spin_lock_irqsave(&fm->lock, flags);
+	for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+		if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
+			printk(KERN_INFO DRIVER_NAME
+			       ": demand removing card from socket %d\n", cnt);
+			sock = fm->sockets[cnt];
+			fm->sockets[cnt] = 0;
+			fm->remove_mask &= ~(1 << cnt);
+
+			writel(0x0e00, sock->addr + SOCK_CONTROL);
+
+			writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+				fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+			writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+				fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+			spin_unlock_irqrestore(&fm->lock, flags);
+			device_unregister(&sock->dev);
+			spin_lock_irqsave(&fm->lock, flags);
+		}
+	}
+	spin_unlock_irqrestore(&fm->lock, flags);
+	class_device_put(&fm->cdev);
+}
+
+static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct tifm_adapter *fm = dev_id;
+	unsigned int irq_status;
+	unsigned int sock_irq_status, cnt;
+
+	spin_lock(&fm->lock);
+	irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
+	if (irq_status == 0 || irq_status == (~0)) {
+		spin_unlock(&fm->lock);
+		return IRQ_NONE;
+	}
+
+	if (irq_status & TIFM_IRQ_ENABLE) {
+		writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+
+		for (cnt = 0; cnt <  fm->max_sockets; cnt++) {
+			sock_irq_status = (irq_status >> cnt) &
+					(TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
+
+			if (fm->sockets[cnt]) {
+				if (sock_irq_status &&
+						fm->sockets[cnt]->signal_irq)
+					sock_irq_status = fm->sockets[cnt]->
+						signal_irq(fm->sockets[cnt],
+							sock_irq_status);
+
+				if (irq_status & (1 << cnt))
+					fm->remove_mask |= 1 << cnt;
+			} else {
+				if (irq_status & (1 << cnt))
+					fm->insert_mask |= 1 << cnt;
+			}
+		}
+	}
+	writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
+
+	if (!fm->inhibit_new_cards) {
+		if (!fm->remove_mask && !fm->insert_mask) {
+			writel(TIFM_IRQ_ENABLE,
+				fm->addr + FM_SET_INTERRUPT_ENABLE);
+		} else {
+			queue_work(fm->wq, &fm->media_remover);
+			queue_work(fm->wq, &fm->media_inserter);
+		}
+	}
+
+	spin_unlock(&fm->lock);
+	return IRQ_HANDLED;
+}
+
+static tifm_media_id tifm_7xx1_toggle_sock_power(char *sock_addr, int is_x2)
+{
+	unsigned int s_state;
+	int cnt;
+
+	writel(0x0e00, sock_addr + SOCK_CONTROL);
+
+	for (cnt = 0; cnt < 100; cnt++) {
+		if (!(TIFM_SOCK_STATE_POWERED &
+				readl(sock_addr + SOCK_PRESENT_STATE)))
+			break;
+		msleep(10);
+	}
+
+	s_state = readl(sock_addr + SOCK_PRESENT_STATE);
+	if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
+		return FM_NULL;
+
+	if (is_x2) {
+		writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+	} else {
+		// SmartMedia cards need extra 40 msec
+		if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
+			msleep(40);
+		writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
+		       sock_addr + SOCK_CONTROL);
+		msleep(10);
+		writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
+			sock_addr + SOCK_CONTROL);
+	}
+
+	for (cnt = 0; cnt < 100; cnt++) {
+		if ((TIFM_SOCK_STATE_POWERED &
+				readl(sock_addr + SOCK_PRESENT_STATE)))
+			break;
+		msleep(10);
+	}
+
+	if (!is_x2)
+		writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
+		       sock_addr + SOCK_CONTROL);
+
+	return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
+}
+
+inline static char *tifm_7xx1_sock_addr(char *base_addr, unsigned int sock_num)
+{
+	return base_addr + ((sock_num + 1) << 10);
+}
+
+static void tifm_7xx1_insert_media(void *adapter)
+{
+	struct tifm_adapter *fm = adapter;
+	unsigned long flags;
+	tifm_media_id media_id;
+	char *card_name = "xx";
+	int cnt, ok_to_register;
+	unsigned int insert_mask;
+	struct tifm_dev *new_sock = 0;
+
+	if (!class_device_get(&fm->cdev))
+		return;
+	spin_lock_irqsave(&fm->lock, flags);
+	insert_mask = fm->insert_mask;
+	fm->insert_mask = 0;
+	if (fm->inhibit_new_cards) {
+		spin_unlock_irqrestore(&fm->lock, flags);
+		class_device_put(&fm->cdev);
+		return;
+	}
+	spin_unlock_irqrestore(&fm->lock, flags);
+
+	for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+		if (!(insert_mask & (1 << cnt)))
+			continue;
+
+		media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
+						       fm->max_sockets == 2);
+		if (media_id) {
+			ok_to_register = 0;
+			new_sock = tifm_alloc_device(fm, cnt);
+			if (new_sock) {
+				new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
+									cnt);
+				new_sock->media_id = media_id;
+				switch (media_id) {
+				case 1:
+					card_name = "xd";
+					break;
+				case 2:
+					card_name = "ms";
+					break;
+				case 3:
+					card_name = "sd";
+					break;
+				default:
+					break;
+				}
+				snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
+					"tifm_%s%u:%u", card_name, fm->id, cnt);
+				printk(KERN_INFO DRIVER_NAME
+					": %s card detected in socket %d\n",
+					card_name, cnt);
+				spin_lock_irqsave(&fm->lock, flags);
+				if (!fm->sockets[cnt]) {
+					fm->sockets[cnt] = new_sock;
+					ok_to_register = 1;
+				}
+				spin_unlock_irqrestore(&fm->lock, flags);
+				if (!ok_to_register ||
+					    device_register(&new_sock->dev)) {
+					spin_lock_irqsave(&fm->lock, flags);
+					fm->sockets[cnt] = 0;
+					spin_unlock_irqrestore(&fm->lock,
+								flags);
+					tifm_free_device(&new_sock->dev);
+				}
+			}
+		}
+		writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+		       fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+		writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+		       fm->addr + FM_SET_INTERRUPT_ENABLE);
+	}
+
+	writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+	class_device_put(&fm->cdev);
+}
+
+static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
+{
+	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fm->lock, flags);
+	fm->inhibit_new_cards = 1;
+	fm->remove_mask = 0xf;
+	fm->insert_mask = 0;
+	writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	spin_unlock_irqrestore(&fm->lock, flags);
+	flush_workqueue(fm->wq);
+
+	tifm_7xx1_remove_media(fm);
+
+	pci_set_power_state(dev, PCI_D3hot);
+        pci_disable_device(dev);
+        pci_save_state(dev);
+	return 0;
+}
+
+static int tifm_7xx1_resume(struct pci_dev *dev)
+{
+	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	unsigned long flags;
+
+	pci_restore_state(dev);
+        pci_enable_device(dev);
+        pci_set_power_state(dev, PCI_D0);
+        pci_set_master(dev);
+
+	spin_lock_irqsave(&fm->lock, flags);
+	fm->inhibit_new_cards = 0;
+	writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
+	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
+		fm->addr + FM_SET_INTERRUPT_ENABLE);
+	fm->insert_mask = 0xf;
+	spin_unlock_irqrestore(&fm->lock, flags);
+	return 0;
+}
+
+static int tifm_7xx1_probe(struct pci_dev *dev,
+			const struct pci_device_id *dev_id)
+{
+	struct tifm_adapter *fm;
+	int pci_dev_busy = 0;
+	int rc;
+
+	rc = pci_set_dma_mask(dev, DMA_32BIT_MASK);
+	if (rc)
+		return rc;
+
+	rc = pci_enable_device(dev);
+	if (rc)
+		return rc;
+
+	pci_set_master(dev);
+
+	rc = pci_request_regions(dev, DRIVER_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	pci_intx(dev, 1);
+
+	fm = tifm_alloc_adapter();
+	if (!fm) {
+		rc = -ENOMEM;
+		goto err_out_int;
+	}
+
+	fm->dev = &dev->dev;
+	fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
+	fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
+				GFP_KERNEL);
+	if (!fm->sockets)
+		goto err_out_free;
+
+	INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media, fm);
+	INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media, fm);
+	fm->eject = tifm_7xx1_eject;
+	pci_set_drvdata(dev, fm);
+
+	fm->addr = ioremap(pci_resource_start(dev, 0),
+				pci_resource_len(dev, 0));
+	if (!fm->addr)
+		goto err_out_free;
+
+	rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
+	if (rc)
+		goto err_out_unmap;
+
+	rc = tifm_add_adapter(fm);
+	if (rc)
+		goto err_out_irq;
+
+	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
+		fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+	fm->insert_mask = 0xf;
+
+	return 0;
+
+err_out_irq:
+	free_irq(dev->irq, fm);
+err_out_unmap:
+	iounmap(fm->addr);
+err_out_free:
+	pci_set_drvdata(dev, NULL);
+	tifm_free_adapter(fm);
+err_out_int:
+	pci_intx(dev, 0);
+	pci_release_regions(dev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(dev);
+	return rc;
+}
+
+static void tifm_7xx1_remove(struct pci_dev *dev)
+{
+	struct tifm_adapter *fm = pci_get_drvdata(dev);
+	unsigned long flags;
+
+	spin_lock_irqsave(&fm->lock, flags);
+	fm->inhibit_new_cards = 1;
+	fm->remove_mask = 0xf;
+	fm->insert_mask = 0;
+	writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	spin_unlock_irqrestore(&fm->lock, flags);
+
+	flush_workqueue(fm->wq);
+
+	tifm_7xx1_remove_media(fm);
+
+	writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+	free_irq(dev->irq, fm);
+
+	tifm_remove_adapter(fm);
+
+	pci_set_drvdata(dev, 0);
+
+	iounmap(fm->addr);
+	pci_intx(dev, 0);
+	pci_release_regions(dev);
+
+	pci_disable_device(dev);
+	tifm_free_adapter(fm);
+}
+
+static struct pci_device_id tifm_7xx1_pci_tbl [] = {
+	{ PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  0 }, /* xx21 - the one I have */
+        { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  0 }, /* xx12 - should be also supported */
+	{ }
+};
+
+static struct pci_driver tifm_7xx1_driver = {
+	.name = DRIVER_NAME,
+	.id_table = tifm_7xx1_pci_tbl,
+	.probe = tifm_7xx1_probe,
+	.remove = tifm_7xx1_remove,
+	.suspend = tifm_7xx1_suspend,
+	.resume = tifm_7xx1_resume,
+};
+
+static int __init tifm_7xx1_init(void)
+{
+	return pci_register_driver(&tifm_7xx1_driver);
+}
+
+static void __exit tifm_7xx1_exit(void)
+{
+	pci_unregister_driver(&tifm_7xx1_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia host driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_7xx1_init);
+module_exit(tifm_7xx1_exit);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
new file mode 100644
index 0000000..cca5f85
--- /dev/null
+++ b/drivers/misc/tifm_core.c
@@ -0,0 +1,272 @@
+/*
+ *  tifm_core.c - TI FlashMedia driver
+ *
+ *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/tifm.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+
+#define DRIVER_NAME "tifm_core"
+#define DRIVER_VERSION "0.6"
+
+static DEFINE_IDR(tifm_adapter_idr);
+static DEFINE_SPINLOCK(tifm_adapter_lock);
+
+static tifm_media_id *tifm_device_match(tifm_media_id *ids,
+			struct tifm_dev *dev)
+{
+	while (*ids) {
+		if (dev->media_id == *ids)
+			return ids;
+		ids++;
+	}
+	return NULL;
+}
+
+static int tifm_match(struct device *dev, struct device_driver *drv)
+{
+	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *fm_drv;
+
+	fm_drv = container_of(drv, struct tifm_driver, driver);
+	if (!fm_drv->id_table)
+		return -EINVAL;
+	if (tifm_device_match(fm_drv->id_table, fm_dev))
+		return 1;
+	return -ENODEV;
+}
+
+static int tifm_uevent(struct device *dev, char **envp, int num_envp,
+		       char *buffer, int buffer_size)
+{
+	struct tifm_dev *fm_dev;
+	int i = 0;
+	int length = 0;
+	const char *card_type_name[] = {"INV", "SM", "MS", "SD"};
+
+	if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev)))
+		return -ENODEV;
+	if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+			"TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id]))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static struct bus_type tifm_bus_type = {
+	.name    = "tifm",
+	.match   = tifm_match,
+	.uevent  = tifm_uevent,
+};
+
+static void tifm_free(struct class_device *cdev)
+{
+	struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
+
+	kfree(fm->sockets);
+	if (fm->wq)
+		destroy_workqueue(fm->wq);
+	kfree(fm);
+}
+
+static struct class tifm_adapter_class = {
+	.name    = "tifm_adapter",
+	.release = tifm_free
+};
+
+struct tifm_adapter *tifm_alloc_adapter(void)
+{
+	struct tifm_adapter *fm;
+
+	fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL);
+	if (fm) {
+		fm->cdev.class = &tifm_adapter_class;
+		spin_lock_init(&fm->lock);
+		class_device_initialize(&fm->cdev);
+	}
+	return fm;
+}
+EXPORT_SYMBOL(tifm_alloc_adapter);
+
+void tifm_free_adapter(struct tifm_adapter *fm)
+{
+	class_device_put(&fm->cdev);
+}
+EXPORT_SYMBOL(tifm_free_adapter);
+
+int tifm_add_adapter(struct tifm_adapter *fm)
+{
+	int rc;
+
+	if (!idr_pre_get(&tifm_adapter_idr, GFP_KERNEL))
+		return -ENOMEM;
+
+	spin_lock(&tifm_adapter_lock);
+	rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id);
+	spin_unlock(&tifm_adapter_lock);
+	if (!rc) {
+		snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
+		strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+
+		fm->wq = create_singlethread_workqueue(fm->wq_name);
+		if (fm->wq)
+			return class_device_add(&fm->cdev);
+
+		spin_lock(&tifm_adapter_lock);
+		idr_remove(&tifm_adapter_idr, fm->id);
+		spin_unlock(&tifm_adapter_lock);
+		rc = -ENOMEM;
+	}
+	return rc;
+}
+EXPORT_SYMBOL(tifm_add_adapter);
+
+void tifm_remove_adapter(struct tifm_adapter *fm)
+{
+	class_device_del(&fm->cdev);
+
+	spin_lock(&tifm_adapter_lock);
+	idr_remove(&tifm_adapter_idr, fm->id);
+	spin_unlock(&tifm_adapter_lock);
+}
+EXPORT_SYMBOL(tifm_remove_adapter);
+
+void tifm_free_device(struct device *dev)
+{
+	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+	if (fm_dev->wq)
+		destroy_workqueue(fm_dev->wq);
+	kfree(fm_dev);
+}
+EXPORT_SYMBOL(tifm_free_device);
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+{
+	struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
+
+	if (dev) {
+		spin_lock_init(&dev->lock);
+		snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
+		dev->wq = create_singlethread_workqueue(dev->wq_name);
+		if (!dev->wq) {
+			kfree(dev);
+			return 0;
+		}
+		dev->dev.parent = fm->dev;
+		dev->dev.bus = &tifm_bus_type;
+		dev->dev.release = tifm_free_device;
+	}
+	return dev;
+}
+EXPORT_SYMBOL(tifm_alloc_device);
+
+void tifm_eject(struct tifm_dev *sock)
+{
+	struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
+	fm->eject(fm, sock);
+}
+EXPORT_SYMBOL(tifm_eject);
+
+int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+		int direction)
+{
+	return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
+}
+EXPORT_SYMBOL(tifm_map_sg);
+
+void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+		   int direction)
+{
+	pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
+}
+EXPORT_SYMBOL(tifm_unmap_sg);
+
+static int tifm_device_probe(struct device *dev)
+{
+	struct tifm_driver *drv;
+	struct tifm_dev *fm_dev;
+	int rc = 0;
+	const tifm_media_id *id;
+
+	drv = container_of(dev->driver, struct tifm_driver, driver);
+	fm_dev = container_of(dev, struct tifm_dev, dev);
+	get_device(dev);
+	if (!fm_dev->drv && drv->probe && drv->id_table) {
+		rc = -ENODEV;
+		id = tifm_device_match(drv->id_table, fm_dev);
+		if (id)
+			rc = drv->probe(fm_dev);
+		if (rc >= 0) {
+			rc = 0;
+			fm_dev->drv = drv;
+		}
+	}
+	if (rc)
+		put_device(dev);
+	return rc;
+}
+
+static int tifm_device_remove(struct device *dev)
+{
+	struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+	struct tifm_driver *drv = fm_dev->drv;
+
+	if (drv) {
+		if (drv->remove) drv->remove(fm_dev);
+		fm_dev->drv = 0;
+	}
+
+	put_device(dev);
+	return 0;
+}
+
+int tifm_register_driver(struct tifm_driver *drv)
+{
+	drv->driver.bus = &tifm_bus_type;
+	drv->driver.probe = tifm_device_probe;
+	drv->driver.remove = tifm_device_remove;
+
+	return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(tifm_register_driver);
+
+void tifm_unregister_driver(struct tifm_driver *drv)
+{
+	driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(tifm_unregister_driver);
+
+static int __init tifm_init(void)
+{
+	int rc = bus_register(&tifm_bus_type);
+
+	if (!rc) {
+		rc = class_register(&tifm_adapter_class);
+		if (rc)
+			bus_unregister(&tifm_bus_type);
+	}
+
+	return rc;
+}
+
+static void __exit tifm_exit(void)
+{
+	class_unregister(&tifm_adapter_class);
+	bus_unregister(&tifm_bus_type);
+}
+
+subsys_initcall(tifm_init);
+module_exit(tifm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia core driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index f540bd8..ea41852 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -109,4 +109,20 @@
 
 	  If unsure, say N.
 
+config MMC_TIFM_SD
+	tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
+	depends on MMC && EXPERIMENTAL
+	select TIFM_CORE
+	help
+	  Say Y here if you want to be able to access MMC/SD cards with
+	  the Texas Instruments(R) Flash Media card reader, found in many
+	  laptops.
+	  This option 'selects' (turns on, enables) 'TIFM_CORE', but you
+	  probably also need appropriate card reader host adapter, such as
+	  'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
+	  (TIFM_7XX1)'.
+
+          To compile this driver as a module, choose M here: the
+	  module will be called tifm_sd.
+
 endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index b1f6e03..acfd4de 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -23,6 +23,7 @@
 obj-$(CONFIG_MMC_AU1X)		+= au1xmmc.o
 obj-$(CONFIG_MMC_OMAP)		+= omap.o
 obj-$(CONFIG_MMC_AT91RM9200)	+= at91_mci.o
+obj-$(CONFIG_MMC_TIFM_SD)	+= tifm_sd.o
 
 mmc_core-y := mmc.o mmc_sysfs.o
 mmc_core-$(CONFIG_BLOCK) += mmc_queue.o
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 5b9caa7..ee8863c 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -1166,9 +1166,9 @@
 void mmc_detect_change(struct mmc_host *host, unsigned long delay)
 {
 	if (delay)
-		schedule_delayed_work(&host->detect, delay);
+		mmc_schedule_delayed_work(&host->detect, delay);
 	else
-		schedule_work(&host->detect);
+		mmc_schedule_work(&host->detect);
 }
 
 EXPORT_SYMBOL(mmc_detect_change);
@@ -1311,7 +1311,7 @@
  */
 void mmc_free_host(struct mmc_host *host)
 {
-	flush_scheduled_work();
+	mmc_flush_scheduled_work();
 	mmc_free_host_sysfs(host);
 }
 
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
index 97bae00..cd5e0ab 100644
--- a/drivers/mmc/mmc.h
+++ b/drivers/mmc/mmc.h
@@ -18,4 +18,8 @@
 int mmc_add_host_sysfs(struct mmc_host *host);
 void mmc_remove_host_sysfs(struct mmc_host *host);
 void mmc_free_host_sysfs(struct mmc_host *host);
+
+int mmc_schedule_work(struct work_struct *work);
+int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay);
+void mmc_flush_scheduled_work(void);
 #endif
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index db0e8ad..c1293f1 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -158,13 +158,13 @@
 {
 	struct mmc_blk_data *md = mq->data;
 	struct mmc_card *card = md->queue.card;
+	struct mmc_blk_request brq;
 	int ret;
 
 	if (mmc_card_claim_host(card))
 		goto cmd_err;
 
 	do {
-		struct mmc_blk_request brq;
 		struct mmc_command cmd;
 		u32 readcmd, writecmd;
 
@@ -278,17 +278,27 @@
  cmd_err:
 	mmc_card_release_host(card);
 
+	ret = 1;
+
 	/*
-	 * This is a little draconian, but until we get proper
-	 * error handling sorted out here, its the best we can
-	 * do - especially as some hosts have no idea how much
-	 * data was transferred before the error occurred.
+	 * For writes and where the host claims to support proper
+	 * error reporting, we first ok the successful blocks.
+	 *
+	 * For reads we just fail the entire chunk as that should
+	 * be safe in all cases.
 	 */
+	if (rq_data_dir(req) != READ &&
+	    (card->host->caps & MMC_CAP_MULTIWRITE)) {
+		spin_lock_irq(&md->lock);
+		ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+		spin_unlock_irq(&md->lock);
+	}
+
 	spin_lock_irq(&md->lock);
-	do {
+	while (ret) {
 		ret = end_that_request_chunk(req, 0,
 				req->current_nr_sectors << 9);
-	} while (ret);
+	}
 
 	add_disk_randomness(req->rq_disk);
 	blkdev_dequeue_request(req);
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index a2a35fd..10cc973 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/idr.h>
+#include <linux/workqueue.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -317,10 +318,41 @@
 	class_device_put(&host->class_dev);
 }
 
+static struct workqueue_struct *workqueue;
+
+/*
+ * Internal function. Schedule work in the MMC work queue.
+ */
+int mmc_schedule_work(struct work_struct *work)
+{
+	return queue_work(workqueue, work);
+}
+
+/*
+ * Internal function. Schedule delayed work in the MMC work queue.
+ */
+int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay)
+{
+	return queue_delayed_work(workqueue, work, delay);
+}
+
+/*
+ * Internal function. Flush all scheduled work from the MMC work queue.
+ */
+void mmc_flush_scheduled_work(void)
+{
+	flush_workqueue(workqueue);
+}
 
 static int __init mmc_init(void)
 {
-	int ret = bus_register(&mmc_bus_type);
+	int ret;
+
+	workqueue = create_singlethread_workqueue("kmmcd");
+	if (!workqueue)
+		return -ENOMEM;
+
+	ret = bus_register(&mmc_bus_type);
 	if (ret == 0) {
 		ret = class_register(&mmc_host_class);
 		if (ret)
@@ -333,6 +365,7 @@
 {
 	class_unregister(&mmc_host_class);
 	bus_unregister(&mmc_bus_type);
+	destroy_workqueue(workqueue);
 }
 
 module_init(mmc_init);
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 4dab5ec..20711ac 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -35,6 +35,8 @@
 
 #define SDHCI_QUIRK_CLOCK_BEFORE_RESET			(1<<0)
 #define SDHCI_QUIRK_FORCE_DMA				(1<<1)
+/* Controller doesn't like some resets when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET			(1<<2)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
@@ -51,7 +53,8 @@
 		.device		= PCI_DEVICE_ID_RICOH_R5C822,
 		.subvendor	= PCI_ANY_ID,
 		.subdevice	= PCI_ANY_ID,
-		.driver_data	= SDHCI_QUIRK_FORCE_DMA,
+		.driver_data	= SDHCI_QUIRK_FORCE_DMA |
+				  SDHCI_QUIRK_NO_CARD_NO_RESET,
 	},
 
 	{
@@ -125,6 +128,12 @@
 {
 	unsigned long timeout;
 
+	if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+		if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+			SDHCI_CARD_PRESENT))
+			return;
+	}
+
 	writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
 
 	if (mask & SDHCI_RESET_ALL)
@@ -717,6 +726,7 @@
 	} else
 		sdhci_send_command(host, mrq->cmd);
 
+	mmiowb();
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -753,6 +763,7 @@
 		ctrl &= ~SDHCI_CTRL_4BITBUS;
 	writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
 
+	mmiowb();
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -860,6 +871,7 @@
 
 	sdhci_deactivate_led(host);
 
+	mmiowb();
 	spin_unlock_irqrestore(&host->lock, flags);
 
 	mmc_request_done(host->mmc, mrq);
@@ -893,6 +905,7 @@
 		}
 	}
 
+	mmiowb();
 	spin_unlock_irqrestore(&host->lock, flags);
 }
 
@@ -1030,6 +1043,7 @@
 
 	result = IRQ_HANDLED;
 
+	mmiowb();
 out:
 	spin_unlock(&host->lock);
 
@@ -1095,6 +1109,7 @@
 		if (chip->hosts[i]->flags & SDHCI_USE_DMA)
 			pci_set_master(pdev);
 		sdhci_init(chip->hosts[i]);
+		mmiowb();
 		ret = mmc_resume_host(chip->hosts[i]->mmc);
 		if (ret)
 			return ret;
@@ -1168,6 +1183,9 @@
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
 
+	host->chip = chip;
+	chip->hosts[slot] = host;
+
 	host->bar = first_bar + slot;
 
 	host->addr = pci_resource_start(pdev, host->bar);
@@ -1324,8 +1342,7 @@
 	sdhci_dumpregs(host);
 #endif
 
-	host->chip = chip;
-	chip->hosts[slot] = host;
+	mmiowb();
 
 	mmc_add_host(mmc);
 
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
new file mode 100644
index 0000000..6d23dc0
--- /dev/null
+++ b/drivers/mmc/tifm_sd.c
@@ -0,0 +1,933 @@
+/*
+ *  tifm_sd.c - TI FlashMedia driver
+ *
+ *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.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
+ * published by the Free Software Foundation.
+ *
+ */
+
+
+#include <linux/tifm.h>
+#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
+#include <linux/highmem.h>
+
+#define DRIVER_NAME "tifm_sd"
+#define DRIVER_VERSION "0.6"
+
+static int no_dma = 0;
+static int fixed_timeout = 0;
+module_param(no_dma, bool, 0644);
+module_param(fixed_timeout, bool, 0644);
+
+/* Constants here are mostly from OMAP5912 datasheet */
+#define TIFM_MMCSD_RESET      0x0002
+#define TIFM_MMCSD_CLKMASK    0x03ff
+#define TIFM_MMCSD_POWER      0x0800
+#define TIFM_MMCSD_4BBUS      0x8000
+#define TIFM_MMCSD_RXDE       0x8000   /* rx dma enable */
+#define TIFM_MMCSD_TXDE       0x0080   /* tx dma enable */
+#define TIFM_MMCSD_BUFINT     0x0c00   /* set bits: AE, AF */
+#define TIFM_MMCSD_DPE        0x0020   /* data timeout counted in kilocycles */
+#define TIFM_MMCSD_INAB       0x0080   /* abort / initialize command */
+#define TIFM_MMCSD_READ       0x8000
+
+#define TIFM_MMCSD_DATAMASK   0x001d   /* set bits: EOFB, BRS, CB, EOC */
+#define TIFM_MMCSD_ERRMASK    0x41e0   /* set bits: CERR, CCRC, CTO, DCRC, DTO */
+#define TIFM_MMCSD_EOC        0x0001   /* end of command phase  */
+#define TIFM_MMCSD_CB         0x0004   /* card enter busy state */
+#define TIFM_MMCSD_BRS        0x0008   /* block received/sent   */
+#define TIFM_MMCSD_EOFB       0x0010   /* card exit busy state  */
+#define TIFM_MMCSD_DTO        0x0020   /* data time-out         */
+#define TIFM_MMCSD_DCRC       0x0040   /* data crc error        */
+#define TIFM_MMCSD_CTO        0x0080   /* command time-out      */
+#define TIFM_MMCSD_CCRC       0x0100   /* command crc error     */
+#define TIFM_MMCSD_AF         0x0400   /* fifo almost full      */
+#define TIFM_MMCSD_AE         0x0800   /* fifo almost empty     */
+#define TIFM_MMCSD_CERR       0x4000   /* card status error     */
+
+#define TIFM_MMCSD_FIFO_SIZE  0x0020
+
+#define TIFM_MMCSD_RSP_R0     0x0000
+#define TIFM_MMCSD_RSP_R1     0x0100
+#define TIFM_MMCSD_RSP_R2     0x0200
+#define TIFM_MMCSD_RSP_R3     0x0300
+#define TIFM_MMCSD_RSP_R4     0x0400
+#define TIFM_MMCSD_RSP_R5     0x0500
+#define TIFM_MMCSD_RSP_R6     0x0600
+
+#define TIFM_MMCSD_RSP_BUSY   0x0800
+
+#define TIFM_MMCSD_CMD_BC     0x0000
+#define TIFM_MMCSD_CMD_BCR    0x1000
+#define TIFM_MMCSD_CMD_AC     0x2000
+#define TIFM_MMCSD_CMD_ADTC   0x3000
+
+typedef enum {
+	IDLE = 0,
+	CMD,    /* main command ended                   */
+	BRS,    /* block transfer finished              */
+	SCMD,   /* stop command ended                   */
+	CARD,   /* card left busy state                 */
+	FIFO,   /* FIFO operation completed (uncertain) */
+	READY
+} card_state_t;
+
+enum {
+	FIFO_RDY   = 0x0001,     /* hardware dependent value */
+	HOST_REG   = 0x0002,
+	EJECT      = 0x0004,
+	EJECT_DONE = 0x0008,
+	CARD_BUSY  = 0x0010,
+	OPENDRAIN  = 0x0040,     /* hardware dependent value */
+	CARD_EVENT = 0x0100,     /* hardware dependent value */
+	CARD_RO    = 0x0200,     /* hardware dependent value */
+	FIFO_EVENT = 0x10000 };  /* hardware dependent value */
+
+struct tifm_sd {
+	struct tifm_dev     *dev;
+
+	unsigned int        flags;
+	card_state_t        state;
+	unsigned int        clk_freq;
+	unsigned int        clk_div;
+	unsigned long       timeout_jiffies; // software timeout - 2 sec
+
+	struct mmc_request    *req;
+	struct work_struct    cmd_handler;
+	struct work_struct    abort_handler;
+	wait_queue_head_t     can_eject;
+
+	size_t                written_blocks;
+	char                  *buffer;
+	size_t                buffer_size;
+	size_t                buffer_pos;
+
+};
+
+static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
+					unsigned int host_status)
+{
+	struct mmc_command *cmd = host->req->cmd;
+	unsigned int t_val = 0, cnt = 0;
+
+	if (host_status & TIFM_MMCSD_BRS) {
+		/* in non-dma rx mode BRS fires when fifo is still not empty */
+		if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
+			while (host->buffer_size > host->buffer_pos) {
+				t_val = readl(sock->addr + SOCK_MMCSD_DATA);
+				host->buffer[host->buffer_pos++] = t_val & 0xff;
+				host->buffer[host->buffer_pos++] =
+							(t_val >> 8) & 0xff;
+			}
+		}
+		return 1;
+	} else if (host->buffer) {
+		if ((cmd->data->flags & MMC_DATA_READ) &&
+				(host_status & TIFM_MMCSD_AF)) {
+			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
+				t_val = readl(sock->addr + SOCK_MMCSD_DATA);
+				if (host->buffer_size > host->buffer_pos) {
+					host->buffer[host->buffer_pos++] =
+							t_val & 0xff;
+					host->buffer[host->buffer_pos++] =
+							(t_val >> 8) & 0xff;
+				}
+			}
+		} else if ((cmd->data->flags & MMC_DATA_WRITE)
+			   && (host_status & TIFM_MMCSD_AE)) {
+			for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
+				if (host->buffer_size > host->buffer_pos) {
+					t_val = host->buffer[host->buffer_pos++] & 0x00ff;
+					t_val |= ((host->buffer[host->buffer_pos++]) << 8)
+						 & 0xff00;
+					writel(t_val,
+						sock->addr + SOCK_MMCSD_DATA);
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
+{
+	unsigned int rc = 0;
+
+	switch (mmc_resp_type(cmd)) {
+	case MMC_RSP_NONE:
+		rc |= TIFM_MMCSD_RSP_R0;
+		break;
+	case MMC_RSP_R1B:
+		rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
+	case MMC_RSP_R1:
+		rc |= TIFM_MMCSD_RSP_R1;
+		break;
+	case MMC_RSP_R2:
+		rc |= TIFM_MMCSD_RSP_R2;
+		break;
+	case MMC_RSP_R3:
+		rc |= TIFM_MMCSD_RSP_R3;
+		break;
+	case MMC_RSP_R6:
+		rc |= TIFM_MMCSD_RSP_R6;
+		break;
+	default:
+		BUG();
+	}
+
+	switch (mmc_cmd_type(cmd)) {
+	case MMC_CMD_BC:
+		rc |= TIFM_MMCSD_CMD_BC;
+		break;
+	case MMC_CMD_BCR:
+		rc |= TIFM_MMCSD_CMD_BCR;
+		break;
+	case MMC_CMD_AC:
+		rc |= TIFM_MMCSD_CMD_AC;
+		break;
+	case MMC_CMD_ADTC:
+		rc |= TIFM_MMCSD_CMD_ADTC;
+		break;
+	default:
+		BUG();
+	}
+	return rc;
+}
+
+static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
+{
+	struct tifm_dev *sock = host->dev;
+	unsigned int cmd_mask = tifm_sd_op_flags(cmd) |
+				(host->flags & OPENDRAIN);
+
+	if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
+		cmd_mask |= TIFM_MMCSD_READ;
+
+	dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
+				cmd->opcode, cmd->arg, cmd_mask);
+
+	writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
+	writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
+	writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
+}
+
+static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
+{
+	cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
+		       | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
+	cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
+		       | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
+	cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
+		       | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
+	cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
+		       | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
+}
+
+static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
+				       unsigned int host_status)
+{
+	struct mmc_command *cmd = host->req->cmd;
+
+change_state:
+	switch (host->state) {
+	case IDLE:
+		return;
+	case CMD:
+		if (host_status & TIFM_MMCSD_EOC) {
+			tifm_sd_fetch_resp(cmd, sock);
+			if (cmd->data) {
+				host->state = BRS;
+			} else
+				host->state = READY;
+			goto change_state;
+		}
+		break;
+	case BRS:
+		if (tifm_sd_transfer_data(sock, host, host_status)) {
+			if (!host->req->stop) {
+				if (cmd->data->flags & MMC_DATA_WRITE) {
+					host->state = CARD;
+				} else {
+					host->state =
+						host->buffer ? READY : FIFO;
+				}
+				goto change_state;
+			}
+			tifm_sd_exec(host, host->req->stop);
+			host->state = SCMD;
+		}
+		break;
+	case SCMD:
+		if (host_status & TIFM_MMCSD_EOC) {
+			tifm_sd_fetch_resp(host->req->stop, sock);
+			if (cmd->error) {
+				host->state = READY;
+			} else if (cmd->data->flags & MMC_DATA_WRITE) {
+				host->state = CARD;
+			} else {
+				host->state = host->buffer ? READY : FIFO;
+			}
+			goto change_state;
+		}
+		break;
+	case CARD:
+		if (!(host->flags & CARD_BUSY)
+		    && (host->written_blocks == cmd->data->blocks)) {
+			host->state = host->buffer ? READY : FIFO;
+			goto change_state;
+		}
+		break;
+	case FIFO:
+		if (host->flags & FIFO_RDY) {
+			host->state = READY;
+			host->flags &= ~FIFO_RDY;
+			goto change_state;
+		}
+		break;
+	case READY:
+		queue_work(sock->wq, &host->cmd_handler);
+		return;
+	}
+
+	queue_delayed_work(sock->wq, &host->abort_handler,
+				host->timeout_jiffies);
+}
+
+/* Called from interrupt handler */
+static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
+					unsigned int sock_irq_status)
+{
+	struct tifm_sd *host;
+	unsigned int host_status = 0, fifo_status = 0;
+	int error_code = 0;
+
+	spin_lock(&sock->lock);
+	host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+	cancel_delayed_work(&host->abort_handler);
+
+	if (sock_irq_status & FIFO_EVENT) {
+		fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
+		writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+
+		host->flags |= fifo_status & FIFO_RDY;
+	}
+
+	if (sock_irq_status & CARD_EVENT) {
+		host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+		writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+
+		if (!(host->flags & HOST_REG))
+			queue_work(sock->wq, &host->cmd_handler);
+		if (!host->req)
+			goto done;
+
+		if (host_status & TIFM_MMCSD_ERRMASK) {
+			if (host_status & TIFM_MMCSD_CERR)
+				error_code = MMC_ERR_FAILED;
+			else if (host_status &
+					(TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
+				error_code = MMC_ERR_TIMEOUT;
+			else if (host_status &
+					(TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
+				error_code = MMC_ERR_BADCRC;
+
+			writel(TIFM_FIFO_INT_SETALL,
+			       sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+			writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
+
+			if (host->req->stop) {
+				if (host->state == SCMD) {
+					host->req->stop->error = error_code;
+				} else if(host->state == BRS) {
+					host->req->cmd->error = error_code;
+					tifm_sd_exec(host, host->req->stop);
+					queue_delayed_work(sock->wq,
+						&host->abort_handler,
+						host->timeout_jiffies);
+					host->state = SCMD;
+					goto done;
+				} else {
+					host->req->cmd->error = error_code;
+				}
+			} else {
+				host->req->cmd->error = error_code;
+			}
+			host->state = READY;
+		}
+
+		if (host_status & TIFM_MMCSD_CB)
+			host->flags |= CARD_BUSY;
+		if ((host_status & TIFM_MMCSD_EOFB) &&
+				(host->flags & CARD_BUSY)) {
+			host->written_blocks++;
+			host->flags &= ~CARD_BUSY;
+		}
+        }
+
+	if (host->req)
+		tifm_sd_process_cmd(sock, host, host_status);
+done:
+	dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
+			host_status, fifo_status);
+	spin_unlock(&sock->lock);
+	return sock_irq_status;
+}
+
+static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
+{
+	struct tifm_dev *sock = card->dev;
+	unsigned int dest_cnt;
+
+	/* DMA style IO */
+
+	writel(TIFM_FIFO_INT_SETALL,
+		sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+	writel(long_log2(cmd->data->blksz) - 2,
+			sock->addr + SOCK_FIFO_PAGE_SIZE);
+	writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
+	writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+	dest_cnt = (cmd->data->blocks) << 8;
+
+	writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS);
+
+	writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+	writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
+
+	if (cmd->data->flags & MMC_DATA_WRITE) {
+		writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+		writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
+			sock->addr + SOCK_DMA_CONTROL);
+	} else {
+		writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+		writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
+	}
+}
+
+static void tifm_sd_set_data_timeout(struct tifm_sd *host,
+					struct mmc_data *data)
+{
+	struct tifm_dev *sock = host->dev;
+	unsigned int data_timeout = data->timeout_clks;
+
+	if (fixed_timeout)
+		return;
+
+	data_timeout += data->timeout_ns /
+			((1000000000 / host->clk_freq) * host->clk_div);
+	data_timeout *= 10; // call it fudge factor for now
+
+	if (data_timeout < 0xffff) {
+		writel((~TIFM_MMCSD_DPE) &
+				readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+		       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+	} else {
+		writel(TIFM_MMCSD_DPE |
+				readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+			sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+		data_timeout = (data_timeout >> 10) + 1;
+		if(data_timeout > 0xffff)
+			data_timeout = 0;	/* set to unlimited */
+		writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+	}
+}
+
+static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct tifm_sd *host = mmc_priv(mmc);
+	struct tifm_dev *sock = host->dev;
+	unsigned long flags;
+	int sg_count = 0;
+	struct mmc_data *r_data = mrq->cmd->data;
+
+	spin_lock_irqsave(&sock->lock, flags);
+	if (host->flags & EJECT) {
+		spin_unlock_irqrestore(&sock->lock, flags);
+		goto err_out;
+	}
+
+	if (host->req) {
+		printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
+		spin_unlock_irqrestore(&sock->lock, flags);
+		goto err_out;
+	}
+
+	if (r_data) {
+		tifm_sd_set_data_timeout(host, r_data);
+
+		sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len,
+				       mrq->cmd->flags & MMC_DATA_WRITE
+				       ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		if (sg_count != 1) {
+			printk(KERN_ERR DRIVER_NAME
+				": scatterlist map failed\n");
+			spin_unlock_irqrestore(&sock->lock, flags);
+			goto err_out;
+		}
+
+		host->written_blocks = 0;
+		host->flags &= ~CARD_BUSY;
+		tifm_sd_prepare_data(host, mrq->cmd);
+	}
+
+	host->req = mrq;
+	host->state = CMD;
+	queue_delayed_work(sock->wq, &host->abort_handler,
+				host->timeout_jiffies);
+	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+		sock->addr + SOCK_CONTROL);
+	tifm_sd_exec(host, mrq->cmd);
+	spin_unlock_irqrestore(&sock->lock, flags);
+	return;
+
+err_out:
+	if (sg_count > 0)
+		tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+			      (r_data->flags & MMC_DATA_WRITE)
+			      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+	mrq->cmd->error = MMC_ERR_TIMEOUT;
+	mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd(void *data)
+{
+	struct tifm_sd *host = data;
+	struct tifm_dev *sock = host->dev;
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	struct mmc_request *mrq;
+	struct mmc_data *r_data = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sock->lock, flags);
+
+	mrq = host->req;
+	host->req = 0;
+	host->state = IDLE;
+
+	if (!mrq) {
+		printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
+		spin_unlock_irqrestore(&sock->lock, flags);
+		return;
+	}
+
+	r_data = mrq->cmd->data;
+	if (r_data) {
+		if (r_data->flags & MMC_DATA_WRITE) {
+			r_data->bytes_xfered = host->written_blocks *
+						r_data->blksz;
+		} else {
+			r_data->bytes_xfered = r_data->blocks -
+				readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+			r_data->bytes_xfered *= r_data->blksz;
+			r_data->bytes_xfered += r_data->blksz -
+				readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+		}
+		tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+			      (r_data->flags & MMC_DATA_WRITE)
+			      ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+	}
+
+	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+			sock->addr + SOCK_CONTROL);
+
+	spin_unlock_irqrestore(&sock->lock, flags);
+	mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+	struct tifm_sd *host = mmc_priv(mmc);
+	struct tifm_dev *sock = host->dev;
+	unsigned long flags;
+	struct mmc_data *r_data = mrq->cmd->data;
+	char *t_buffer = 0;
+
+	if (r_data) {
+		t_buffer = kmap(r_data->sg->page);
+		if (!t_buffer) {
+			printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
+			goto err_out;
+		}
+	}
+
+	spin_lock_irqsave(&sock->lock, flags);
+	if (host->flags & EJECT) {
+		spin_unlock_irqrestore(&sock->lock, flags);
+		goto err_out;
+	}
+
+	if (host->req) {
+		printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
+		spin_unlock_irqrestore(&sock->lock, flags);
+		goto err_out;
+	}
+
+	if (r_data) {
+		tifm_sd_set_data_timeout(host, r_data);
+
+		host->buffer = t_buffer + r_data->sg->offset;
+		host->buffer_size = mrq->cmd->data->blocks *
+					mrq->cmd->data->blksz;
+
+		writel(TIFM_MMCSD_BUFINT |
+				readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+		       sock->addr + SOCK_MMCSD_INT_ENABLE);
+		writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
+				(TIFM_MMCSD_FIFO_SIZE - 1),
+		       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+		host->written_blocks = 0;
+		host->flags &= ~CARD_BUSY;
+		host->buffer_pos = 0;
+		writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+		writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
+	}
+
+	host->req = mrq;
+	host->state = CMD;
+	queue_delayed_work(sock->wq, &host->abort_handler,
+				host->timeout_jiffies);
+	writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+		sock->addr + SOCK_CONTROL);
+	tifm_sd_exec(host, mrq->cmd);
+	spin_unlock_irqrestore(&sock->lock, flags);
+	return;
+
+err_out:
+	if (t_buffer)
+		kunmap(r_data->sg->page);
+
+	mrq->cmd->error = MMC_ERR_TIMEOUT;
+	mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd_nodma(void *data)
+{
+	struct tifm_sd *host = (struct tifm_sd*)data;
+	struct tifm_dev *sock = host->dev;
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	struct mmc_request *mrq;
+	struct mmc_data *r_data = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sock->lock, flags);
+
+	mrq = host->req;
+	host->req = 0;
+	host->state = IDLE;
+
+	if (!mrq) {
+		printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
+		spin_unlock_irqrestore(&sock->lock, flags);
+		return;
+	}
+
+	r_data = mrq->cmd->data;
+	if (r_data) {
+		writel((~TIFM_MMCSD_BUFINT) &
+			readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+			sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+		if (r_data->flags & MMC_DATA_WRITE) {
+			r_data->bytes_xfered = host->written_blocks *
+						r_data->blksz;
+		} else {
+			r_data->bytes_xfered = r_data->blocks -
+				readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+			r_data->bytes_xfered *= r_data->blksz;
+			r_data->bytes_xfered += r_data->blksz -
+				readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+		}
+		host->buffer = 0;
+		host->buffer_pos = 0;
+		host->buffer_size = 0;
+	}
+
+	writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+			sock->addr + SOCK_CONTROL);
+
+	spin_unlock_irqrestore(&sock->lock, flags);
+
+        if (r_data)
+		kunmap(r_data->sg->page);
+
+	mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_abort(void *data)
+{
+	printk(KERN_ERR DRIVER_NAME
+		": card failed to respond for a long period of time");
+	tifm_eject(((struct tifm_sd*)data)->dev);
+}
+
+static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+	struct tifm_sd *host = mmc_priv(mmc);
+	struct tifm_dev *sock = host->dev;
+	unsigned int clk_div1, clk_div2;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sock->lock, flags);
+
+	dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width,
+		ios->power_mode);
+	if (ios->bus_width == MMC_BUS_WIDTH_4) {
+		writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
+		       sock->addr + SOCK_MMCSD_CONFIG);
+	} else {
+		writel((~TIFM_MMCSD_4BBUS) &
+				readl(sock->addr + SOCK_MMCSD_CONFIG),
+			sock->addr + SOCK_MMCSD_CONFIG);
+	}
+
+	if (ios->clock) {
+		clk_div1 = 20000000 / ios->clock;
+		if (!clk_div1)
+			clk_div1 = 1;
+
+		clk_div2 = 24000000 / ios->clock;
+		if (!clk_div2)
+			clk_div2 = 1;
+
+		if ((20000000 / clk_div1) > ios->clock)
+			clk_div1++;
+		if ((24000000 / clk_div2) > ios->clock)
+			clk_div2++;
+		if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
+			host->clk_freq = 20000000;
+			host->clk_div = clk_div1;
+			writel((~TIFM_CTRL_FAST_CLK) &
+					readl(sock->addr + SOCK_CONTROL),
+				sock->addr + SOCK_CONTROL);
+		} else {
+			host->clk_freq = 24000000;
+			host->clk_div = clk_div2;
+			writel(TIFM_CTRL_FAST_CLK |
+					readl(sock->addr + SOCK_CONTROL),
+				sock->addr + SOCK_CONTROL);
+		}
+	} else {
+		host->clk_div = 0;
+	}
+	host->clk_div &= TIFM_MMCSD_CLKMASK;
+	writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
+			readl(sock->addr + SOCK_MMCSD_CONFIG)),
+		sock->addr + SOCK_MMCSD_CONFIG);
+
+	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+		host->flags |= OPENDRAIN;
+	else
+		host->flags &= ~OPENDRAIN;
+
+	/* chip_select : maybe later */
+	//vdd
+	//power is set before probe / after remove
+	//I believe, power_off when already marked for eject is sufficient to
+	// allow removal.
+	if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
+		host->flags |= EJECT_DONE;
+		wake_up_all(&host->can_eject);
+	}
+
+	spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static int tifm_sd_ro(struct mmc_host *mmc)
+{
+	int rc;
+	struct tifm_sd *host = mmc_priv(mmc);
+	struct tifm_dev *sock = host->dev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sock->lock, flags);
+
+	host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE));
+	rc = (host->flags & CARD_RO) ? 1 : 0;
+
+	spin_unlock_irqrestore(&sock->lock, flags);
+	return rc;
+}
+
+static struct mmc_host_ops tifm_sd_ops = {
+	.request = tifm_sd_request,
+	.set_ios = tifm_sd_ios,
+	.get_ro  = tifm_sd_ro
+};
+
+static void tifm_sd_register_host(void *data)
+{
+	struct tifm_sd *host = (struct tifm_sd*)data;
+	struct tifm_dev *sock = host->dev;
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	unsigned long flags;
+
+	spin_lock_irqsave(&sock->lock, flags);
+	host->flags |= HOST_REG;
+	PREPARE_WORK(&host->cmd_handler,
+			no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+			data);
+	spin_unlock_irqrestore(&sock->lock, flags);
+	dev_dbg(&sock->dev, "adding host\n");
+	mmc_add_host(mmc);
+}
+
+static int tifm_sd_probe(struct tifm_dev *sock)
+{
+	struct mmc_host *mmc;
+	struct tifm_sd *host;
+	int rc = -EIO;
+
+	if (!(TIFM_SOCK_STATE_OCCUPIED &
+			readl(sock->addr + SOCK_PRESENT_STATE))) {
+		printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
+		return rc;
+	}
+
+	mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
+	if (!mmc)
+		return -ENOMEM;
+
+	host = mmc_priv(mmc);
+	host->dev = sock;
+	host->clk_div = 61;
+	init_waitqueue_head(&host->can_eject);
+	INIT_WORK(&host->cmd_handler, tifm_sd_register_host, host);
+	INIT_WORK(&host->abort_handler, tifm_sd_abort, host);
+
+	tifm_set_drvdata(sock, mmc);
+	sock->signal_irq = tifm_sd_signal_irq;
+
+	host->clk_freq = 20000000;
+	host->timeout_jiffies = msecs_to_jiffies(1000);
+
+	tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
+	mmc->ops = &tifm_sd_ops;
+	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->caps = MMC_CAP_4_BIT_DATA;
+	mmc->f_min = 20000000 / 60;
+	mmc->f_max = 24000000;
+	mmc->max_hw_segs = 1;
+	mmc->max_phys_segs = 1;
+	mmc->max_sectors = 127;
+	mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
+
+	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+	writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+	writel(host->clk_div | TIFM_MMCSD_POWER,
+			sock->addr + SOCK_MMCSD_CONFIG);
+
+	for (rc = 0; rc < 50; rc++) {
+		/* Wait for reset ack */
+		if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+			rc = 0;
+			break;
+		}
+		msleep(10);
+        }
+
+	if (rc) {
+		printk(KERN_ERR DRIVER_NAME
+			": card not ready - probe failed\n");
+		mmc_free_host(mmc);
+		return -ENODEV;
+	}
+
+	writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+	writel(host->clk_div | TIFM_MMCSD_POWER,
+			sock->addr + SOCK_MMCSD_CONFIG);
+	writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+	writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+			sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+	writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
+	writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+	writel(host->clk_div | TIFM_MMCSD_POWER,
+			sock->addr + SOCK_MMCSD_CONFIG);
+
+	queue_delayed_work(sock->wq, &host->abort_handler,
+			host->timeout_jiffies);
+
+	return 0;
+}
+
+static int tifm_sd_host_is_down(struct tifm_dev *sock)
+{
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	struct tifm_sd *host = mmc_priv(mmc);
+	unsigned long flags;
+	int rc = 0;
+
+	spin_lock_irqsave(&sock->lock, flags);
+	rc = (host->flags & EJECT_DONE);
+	spin_unlock_irqrestore(&sock->lock, flags);
+	return rc;
+}
+
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+	struct mmc_host *mmc = tifm_get_drvdata(sock);
+	struct tifm_sd *host = mmc_priv(mmc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&sock->lock, flags);
+	host->flags |= EJECT;
+	if (host->req)
+		queue_work(sock->wq, &host->cmd_handler);
+	spin_unlock_irqrestore(&sock->lock, flags);
+	wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
+				host->timeout_jiffies);
+
+	if (host->flags & HOST_REG)
+		mmc_remove_host(mmc);
+
+	/* The meaning of the bit majority in this constant is unknown. */
+	writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+		sock->addr + SOCK_CONTROL);
+	writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+	writel(TIFM_FIFO_INT_SETALL,
+		sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+	writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+	tifm_set_drvdata(sock, 0);
+	mmc_free_host(mmc);
+}
+
+static tifm_media_id tifm_sd_id_tbl[] = {
+	FM_SD, 0
+};
+
+static struct tifm_driver tifm_sd_driver = {
+	.driver = {
+		.name  = DRIVER_NAME,
+		.owner = THIS_MODULE
+	},
+	.id_table = tifm_sd_id_tbl,
+	.probe    = tifm_sd_probe,
+	.remove   = tifm_sd_remove
+};
+
+static int __init tifm_sd_init(void)
+{
+	return tifm_register_driver(&tifm_sd_driver);
+}
+
+static void __exit tifm_sd_exit(void)
+{
+	tifm_unregister_driver(&tifm_sd_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia SD driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_sd_init);
+module_exit(tifm_sd_exit);
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index cef0074..d231efa 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -9,7 +9,6 @@
  * (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/dma-mapping.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 1328e10..baaae3d 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -12,8 +12,6 @@
  * kind, whether express or implied.
  */
 
-
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 21dc68e..a43e242 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -21,8 +21,6 @@
  *
  *************************************************************************/
 
-#include <linux/config.h>
-
 #define DRV_NAME	"pcnet32"
 #ifdef CONFIG_PCNET32_NAPI
 #define DRV_VERSION	"1.33-NAPI"
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 94b47c8d0..f14e992 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -13,7 +13,6 @@
  * option) any later version.
  *
  */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
index f91028c..67260eb 100644
--- a/drivers/net/ucc_geth_phy.c
+++ b/drivers/net/ucc_geth_phy.c
@@ -17,7 +17,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 1fbda77..c2949b4 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -146,7 +146,7 @@
 #include <asm/superio.h>
 #endif
 
-#include <asm/iosapic.h>
+#include <asm/ropes.h>
 #include "./iosapic_private.h"
 
 #define MODULE_NAME "iosapic"
@@ -692,6 +692,7 @@
 	DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
 			vi->eoi_addr, vi->eoi_data);
 	iosapic_eoi(vi->eoi_addr, vi->eoi_data);
+	cpu_end_irq(irq);
 }
 
 static unsigned int iosapic_startup_irq(unsigned int irq)
@@ -728,7 +729,7 @@
 	.shutdown =	iosapic_disable_irq,
 	.enable =	iosapic_enable_irq,
 	.disable =	iosapic_disable_irq,
-	.ack =		no_ack_irq,
+	.ack =		cpu_ack_irq,
 	.end =		iosapic_end_irq,
 #ifdef CONFIG_SMP
 	.set_affinity =	iosapic_set_affinity_irq,
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 3fe4a77..ba67699 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -46,9 +46,9 @@
 #include <asm/page.h>
 #include <asm/system.h>
 
+#include <asm/ropes.h>
 #include <asm/hardware.h>	/* for register_parisc_driver() stuff */
 #include <asm/parisc-device.h>
-#include <asm/iosapic.h>	/* for iosapic_register() */
 #include <asm/io.h>		/* read/write stuff */
 
 #undef DEBUG_LBA	/* general stuff */
@@ -100,113 +100,10 @@
 
 #define MODULE_NAME "LBA"
 
-#define LBA_FUNC_ID	0x0000	/* function id */
-#define LBA_FCLASS	0x0008	/* function class, bist, header, rev... */
-#define LBA_CAPABLE	0x0030	/* capabilities register */
-
-#define LBA_PCI_CFG_ADDR	0x0040	/* poke CFG address here */
-#define LBA_PCI_CFG_DATA	0x0048	/* read or write data here */
-
-#define LBA_PMC_MTLT	0x0050	/* Firmware sets this - read only. */
-#define LBA_FW_SCRATCH	0x0058	/* Firmware writes the PCI bus number here. */
-#define LBA_ERROR_ADDR	0x0070	/* On error, address gets logged here */
-
-#define LBA_ARB_MASK	0x0080	/* bit 0 enable arbitration. PAT/PDC enables */
-#define LBA_ARB_PRI	0x0088	/* firmware sets this. */
-#define LBA_ARB_MODE	0x0090	/* firmware sets this. */
-#define LBA_ARB_MTLT	0x0098	/* firmware sets this. */
-
-#define LBA_MOD_ID	0x0100	/* Module ID. PDC_PAT_CELL reports 4 */
-
-#define LBA_STAT_CTL	0x0108	/* Status & Control */
-#define   LBA_BUS_RESET		0x01	/*  Deassert PCI Bus Reset Signal */
-#define   CLEAR_ERRLOG		0x10	/*  "Clear Error Log" cmd */
-#define   CLEAR_ERRLOG_ENABLE	0x20	/*  "Clear Error Log" Enable */
-#define   HF_ENABLE	0x40	/*    enable HF mode (default is -1 mode) */
-
-#define LBA_LMMIO_BASE	0x0200	/* < 4GB I/O address range */
-#define LBA_LMMIO_MASK	0x0208
-
-#define LBA_GMMIO_BASE	0x0210	/* > 4GB I/O address range */
-#define LBA_GMMIO_MASK	0x0218
-
-#define LBA_WLMMIO_BASE	0x0220	/* All < 4GB ranges under the same *SBA* */
-#define LBA_WLMMIO_MASK	0x0228
-
-#define LBA_WGMMIO_BASE	0x0230	/* All > 4GB ranges under the same *SBA* */
-#define LBA_WGMMIO_MASK	0x0238
-
-#define LBA_IOS_BASE	0x0240	/* I/O port space for this LBA */
-#define LBA_IOS_MASK	0x0248
-
-#define LBA_ELMMIO_BASE	0x0250	/* Extra LMMIO range */
-#define LBA_ELMMIO_MASK	0x0258
-
-#define LBA_EIOS_BASE	0x0260	/* Extra I/O port space */
-#define LBA_EIOS_MASK	0x0268
-
-#define LBA_GLOBAL_MASK	0x0270	/* Mercury only: Global Address Mask */
-#define LBA_DMA_CTL	0x0278	/* firmware sets this */
-
-#define LBA_IBASE	0x0300	/* SBA DMA support */
-#define LBA_IMASK	0x0308
-
-/* FIXME: ignore DMA Hint stuff until we can measure performance */
-#define LBA_HINT_CFG	0x0310
-#define LBA_HINT_BASE	0x0380	/* 14 registers at every 8 bytes. */
-
-#define LBA_BUS_MODE	0x0620
-
-/* ERROR regs are needed for config cycle kluges */
-#define LBA_ERROR_CONFIG 0x0680
-#define     LBA_SMART_MODE 0x20
-#define LBA_ERROR_STATUS 0x0688
-#define LBA_ROPE_CTL     0x06A0
-
-#define LBA_IOSAPIC_BASE	0x800 /* Offset of IRQ logic */
-
 /* non-postable I/O port space, densely packed */
 #define LBA_PORT_BASE	(PCI_F_EXTEND | 0xfee00000UL)
 static void __iomem *astro_iop_base __read_mostly;
 
-#define ELROY_HVERS	0x782
-#define MERCURY_HVERS	0x783
-#define QUICKSILVER_HVERS	0x784
-
-static inline int IS_ELROY(struct parisc_device *d)
-{
-	return (d->id.hversion == ELROY_HVERS);
-}
-
-static inline int IS_MERCURY(struct parisc_device *d)
-{
-	return (d->id.hversion == MERCURY_HVERS);
-}
-
-static inline int IS_QUICKSILVER(struct parisc_device *d)
-{
-	return (d->id.hversion == QUICKSILVER_HVERS);
-}
-
-
-/*
-** lba_device: Per instance Elroy data structure
-*/
-struct lba_device {
-	struct pci_hba_data hba;
-
-	spinlock_t	lba_lock;
-	void		*iosapic_obj;
-
-#ifdef CONFIG_64BIT
-	void __iomem *	iop_base;    /* PA_VIEW - for IO port accessor funcs */
-#endif
-
-	int		flags;       /* state/functionality enabled */
-	int		hw_rev;      /* HW revision of chip */
-};
-
-
 static u32 lba_t32;
 
 /* lba flags */
@@ -1542,8 +1439,8 @@
 		default: version = "TR4+";
 		}
 
-		printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
-			MODULE_NAME, version, func_class & 0xf, dev->hpa.start);
+		printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n",
+		       version, func_class & 0xf, dev->hpa.start);
 
 		if (func_class < 2) {
 			printk(KERN_WARNING "Can't support LBA older than "
@@ -1563,14 +1460,18 @@
 		}
 
 	} else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) {
+		int major, minor;
+
 		func_class &= 0xff;
-		version = kmalloc(6, GFP_KERNEL);
-		snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf));
+		major = func_class >> 4, minor = func_class & 0xf;
+
 		/* We could use one printk for both Elroy and Mercury,
                  * but for the mask for func_class.
                  */ 
-		printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
-		       MODULE_NAME, version, func_class & 0xff, dev->hpa.start);
+		printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n",
+		       IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major,
+		       minor, func_class, dev->hpa.start);
+
 		cfg_ops = &mercury_cfg_ops;
 	} else {
 		printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start);
@@ -1600,6 +1501,7 @@
 	lba_dev->hba.dev = dev;
 	lba_dev->iosapic_obj = tmp_obj;  /* save interrupt handle */
 	lba_dev->hba.iommu = sba_get_iommu(dev);  /* get iommu data */
+	parisc_set_drvdata(dev, lba_dev);
 
 	/* ------------ Second : initialize common stuff ---------- */
 	pci_bios = &lba_bios_ops;
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 8b47328..294c111 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -38,22 +38,15 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+#include <asm/ropes.h>
+#include <asm/mckinley.h>	/* for proc_mckinley_root */
 #include <asm/runway.h>		/* for proc_runway_root */
 #include <asm/pdc.h>		/* for PDC_MODEL_* */
 #include <asm/pdcpat.h>		/* for is_pdc_pat() */
 #include <asm/parisc-device.h>
 
-
-/* declared in arch/parisc/kernel/setup.c */
-extern struct proc_dir_entry * proc_mckinley_root;
-
 #define MODULE_NAME "SBA"
 
-#ifdef CONFIG_PROC_FS
-/* depends on proc fs support. But costs CPU performance */
-#undef SBA_COLLECT_STATS
-#endif
-
 /*
 ** The number of debug flags is a clue - this code is fragile.
 ** Don't even think about messing with it unless you have
@@ -92,202 +85,12 @@
 #define DBG_RES(x...)
 #endif
 
-#if defined(CONFIG_64BIT)
-/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
-#define ZX1_SUPPORT
-#endif
-
 #define SBA_INLINE	__inline__
 
-
-/*
-** The number of pdir entries to "free" before issueing
-** a read to PCOM register to flush out PCOM writes.
-** Interacts with allocation granularity (ie 4 or 8 entries
-** allocated and free'd/purged at a time might make this
-** less interesting).
-*/
-#define DELAYED_RESOURCE_CNT	16
-
 #define DEFAULT_DMA_HINT_REG	0
 
-#define ASTRO_RUNWAY_PORT	0x582
-#define IKE_MERCED_PORT		0x803
-#define REO_MERCED_PORT		0x804
-#define REOG_MERCED_PORT	0x805
-#define PLUTO_MCKINLEY_PORT	0x880
-
-#define SBA_FUNC_ID	0x0000	/* function id */
-#define SBA_FCLASS	0x0008	/* function class, bist, header, rev... */
-
-#define IS_ASTRO(id)		((id)->hversion == ASTRO_RUNWAY_PORT)
-#define IS_IKE(id)		((id)->hversion == IKE_MERCED_PORT)
-#define IS_PLUTO(id)		((id)->hversion == PLUTO_MCKINLEY_PORT)
-
-#define SBA_FUNC_SIZE 4096   /* SBA configuration function reg set */
-
-#define ASTRO_IOC_OFFSET	(32 * SBA_FUNC_SIZE)
-#define PLUTO_IOC_OFFSET	(1 * SBA_FUNC_SIZE)
-/* Ike's IOC's occupy functions 2 and 3 */
-#define IKE_IOC_OFFSET(p)	((p+2) * SBA_FUNC_SIZE)
-
-#define IOC_CTRL          0x8	/* IOC_CTRL offset */
-#define IOC_CTRL_TC       (1 << 0) /* TOC Enable */
-#define IOC_CTRL_CE       (1 << 1) /* Coalesce Enable */
-#define IOC_CTRL_DE       (1 << 2) /* Dillon Enable */
-#define IOC_CTRL_RM       (1 << 8) /* Real Mode */
-#define IOC_CTRL_NC       (1 << 9) /* Non Coherent Mode */
-#define IOC_CTRL_D4       (1 << 11) /* Disable 4-byte coalescing */
-#define IOC_CTRL_DD       (1 << 13) /* Disable distr. LMMIO range coalescing */
-
-#define MAX_IOC		2	/* per Ike. Pluto/Astro only have 1. */
-
-#define ROPES_PER_IOC	8	/* per Ike half or Pluto/Astro */
-
-
-/*
-** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
-** Firmware programs this stuff. Don't touch it.
-*/
-#define LMMIO_DIRECT0_BASE  0x300
-#define LMMIO_DIRECT0_MASK  0x308
-#define LMMIO_DIRECT0_ROUTE 0x310
-
-#define LMMIO_DIST_BASE  0x360
-#define LMMIO_DIST_MASK  0x368
-#define LMMIO_DIST_ROUTE 0x370
-
-#define IOS_DIST_BASE	0x390
-#define IOS_DIST_MASK	0x398
-#define IOS_DIST_ROUTE	0x3A0
-
-#define IOS_DIRECT_BASE	0x3C0
-#define IOS_DIRECT_MASK	0x3C8
-#define IOS_DIRECT_ROUTE 0x3D0
-
-/*
-** Offsets into I/O TLB (Function 2 and 3 on Ike)
-*/
-#define ROPE0_CTL	0x200  /* "regbus pci0" */
-#define ROPE1_CTL	0x208
-#define ROPE2_CTL	0x210
-#define ROPE3_CTL	0x218
-#define ROPE4_CTL	0x220
-#define ROPE5_CTL	0x228
-#define ROPE6_CTL	0x230
-#define ROPE7_CTL	0x238
-
-#define IOC_ROPE0_CFG	0x500	/* pluto only */
-#define   IOC_ROPE_AO	  0x10	/* Allow "Relaxed Ordering" */
-
-
-
-#define HF_ENABLE	0x40
-
-
-#define IOC_IBASE	0x300	/* IO TLB */
-#define IOC_IMASK	0x308
-#define IOC_PCOM	0x310
-#define IOC_TCNFG	0x318
-#define IOC_PDIR_BASE	0x320
-
-/* AGP GART driver looks for this */
-#define SBA_IOMMU_COOKIE    0x0000badbadc0ffeeUL
-
-
-/*
-** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
-** It's safer (avoid memory corruption) to keep DMA page mappings
-** equivalently sized to VM PAGE_SIZE.
-**
-** We really can't avoid generating a new mapping for each
-** page since the Virtual Coherence Index has to be generated
-** and updated for each page.
-**
-** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
-*/
-#define IOVP_SIZE	PAGE_SIZE
-#define IOVP_SHIFT	PAGE_SHIFT
-#define IOVP_MASK	PAGE_MASK
-
-#define SBA_PERF_CFG	0x708	/* Performance Counter stuff */
-#define SBA_PERF_MASK1	0x718
-#define SBA_PERF_MASK2	0x730
-
-
-/*
-** Offsets into PCI Performance Counters (functions 12 and 13)
-** Controlled by PERF registers in function 2 & 3 respectively.
-*/
-#define SBA_PERF_CNT1	0x200
-#define SBA_PERF_CNT2	0x208
-#define SBA_PERF_CNT3	0x210
-
-
-struct ioc {
-	void __iomem	*ioc_hpa;	/* I/O MMU base address */
-	char		*res_map;	/* resource map, bit == pdir entry */
-	u64		*pdir_base;	/* physical base address */
-	unsigned long	ibase;	/* pdir IOV Space base - shared w/lba_pci */
-	unsigned long	imask;	/* pdir IOV Space mask - shared w/lba_pci */
-#ifdef ZX1_SUPPORT
-	unsigned long	iovp_mask;	/* help convert IOVA to IOVP */
-#endif
-	unsigned long	*res_hint;	/* next avail IOVP - circular search */
-	spinlock_t	res_lock;
-	unsigned int	res_bitshift;	/* from the LEFT! */
-	unsigned int	res_size;	/* size of resource map in bytes */
-#ifdef SBA_HINT_SUPPORT
-/* FIXME : DMA HINTs not used */
-	unsigned long	hint_mask_pdir;	/* bits used for DMA hints */
-	unsigned int	hint_shift_pdir;
-#endif
-#if DELAYED_RESOURCE_CNT > 0
-	int saved_cnt;
-	struct sba_dma_pair {
-		dma_addr_t	iova;
-		size_t		size;
-	} saved[DELAYED_RESOURCE_CNT];
-#endif
-
-#ifdef SBA_COLLECT_STATS
-#define SBA_SEARCH_SAMPLE	0x100
-	unsigned long avg_search[SBA_SEARCH_SAMPLE];
-	unsigned long avg_idx;	/* current index into avg_search */
-	unsigned long used_pages;
-	unsigned long msingle_calls;
-	unsigned long msingle_pages;
-	unsigned long msg_calls;
-	unsigned long msg_pages;
-	unsigned long usingle_calls;
-	unsigned long usingle_pages;
-	unsigned long usg_calls;
-	unsigned long usg_pages;
-#endif
-
-	/* STUFF We don't need in performance path */
-	unsigned int	pdir_size;	/* in bytes, determined by IOV Space size */
-};
-
-struct sba_device {
-	struct sba_device	*next;	/* list of SBA's in system */
-	struct parisc_device	*dev;	/* dev found in bus walk */
-	struct parisc_device_id	*iodc;	/* data about dev from firmware */
-	const char 		*name;
-	void __iomem		*sba_hpa; /* base address */
-	spinlock_t		sba_lock;
-	unsigned int		flags;  /* state/functionality enabled */
-	unsigned int		hw_rev;  /* HW revision of chip */
-
-	struct resource		chip_resv; /* MMIO reserved for chip */
-	struct resource		iommu_resv; /* MMIO reserved for iommu */
-
-	unsigned int		num_ioc;  /* number of on-board IOC's */
-	struct ioc		ioc[MAX_IOC];
-};
-
-
-static struct sba_device *sba_list;
+struct sba_device *sba_list;
+EXPORT_SYMBOL_GPL(sba_list);
 
 static unsigned long ioc_needs_fdc = 0;
 
@@ -300,8 +103,14 @@
 /* Looks nice and keeps the compiler happy */
 #define SBA_DEV(d) ((struct sba_device *) (d))
 
+#ifdef CONFIG_AGP_PARISC
+#define SBA_AGP_SUPPORT
+#endif /*CONFIG_AGP_PARISC*/
+
 #ifdef SBA_AGP_SUPPORT
-static int reserve_sba_gart = 1;
+static int sba_reserve_agpgart = 1;
+module_param(sba_reserve_agpgart, int, 1);
+MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
 #endif
 
 #define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
@@ -741,7 +550,7 @@
 	asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
 	pa |= (ci >> 12) & 0xff;  /* move CI (8 bits) into lowest byte */
 
-	pa |= 0x8000000000000000ULL;	/* set "valid" bit */
+	pa |= SBA_PDIR_VALID_BIT;	/* set "valid" bit */
 	*pdir_ptr = cpu_to_le64(pa);	/* swap and store into I/O Pdir */
 
 	/*
@@ -1498,6 +1307,10 @@
 	WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);
 
 #ifdef SBA_AGP_SUPPORT
+{
+	struct klist_iter i;
+	struct device *dev = NULL;
+
 	/*
 	** If an AGP device is present, only use half of the IOV space
 	** for PCI DMA.  Unfortunately we can't know ahead of time
@@ -1506,20 +1319,22 @@
 	** We program the next pdir index after we stop w/ a key for
 	** the GART code to handshake on.
 	*/
-	device=NULL;
-	for (lba = sba->child; lba; lba = lba->sibling) {
+	klist_iter_init(&sba->dev.klist_children, &i);
+	while (dev = next_device(&i)) {
+		struct parisc_device *lba = to_parisc_device(dev);
 		if (IS_QUICKSILVER(lba))
-			break;
+			agp_found = 1;
 	}
+	klist_iter_exit(&sba->dev.klist_children, &i);
 
-	if (lba) {
-		DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);
+	if (agp_found && sba_reserve_agpgart) {
+		printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n",
+		       __FUNCTION__, (iova_space_size/2) >> 20);
 		ioc->pdir_size /= 2;
-		((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;
-	} else {
-		DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);
+		ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE;
 	}
-#endif /* 0 */
+}
+#endif /*SBA_AGP_SUPPORT*/
 
 }
 
@@ -1701,7 +1516,7 @@
 	}
 #endif
 
-	if (!IS_PLUTO(sba_dev->iodc)) {
+	if (!IS_PLUTO(sba_dev->dev)) {
 		ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
 		DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
 			__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
@@ -1718,9 +1533,8 @@
 #endif
 	} /* if !PLUTO */
 
-	if (IS_ASTRO(sba_dev->iodc)) {
+	if (IS_ASTRO(sba_dev->dev)) {
 		int err;
-		/* PAT_PDC (L-class) also reports the same goofy base */
 		sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET);
 		num_ioc = 1;
 
@@ -1730,13 +1544,9 @@
 		err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
 		BUG_ON(err < 0);
 
-	} else if (IS_PLUTO(sba_dev->iodc)) {
+	} else if (IS_PLUTO(sba_dev->dev)) {
 		int err;
 
-		/* We use a negative value for IOC HPA so it gets 
-                 * corrected when we add it with IKE's IOC offset.
-		 * Doesnt look clean, but fewer code. 
-                 */
 		sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET);
 		num_ioc = 1;
 
@@ -1752,14 +1562,14 @@
 		err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
 		WARN_ON(err < 0);
 	} else {
-		/* IS_IKE (ie N-class, L3000, L1500) */
+		/* IKE, REO */
 		sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));
 		sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));
 		num_ioc = 2;
 
 		/* TODO - LOOKUP Ike/Stretch chipset mem map */
 	}
-	/* XXX: What about Reo? */
+	/* XXX: What about Reo Grande? */
 
 	sba_dev->num_ioc = num_ioc;
 	for (i = 0; i < num_ioc; i++) {
@@ -1774,7 +1584,7 @@
 			 * Overrides bit 1 in DMA Hint Sets.
 			 * Improves netperf UDP_STREAM by ~10% for bcm5701.
 			 */
-			if (IS_PLUTO(sba_dev->iodc)) {
+			if (IS_PLUTO(sba_dev->dev)) {
 				void __iomem *rope_cfg;
 				unsigned long cfg_val;
 
@@ -1803,7 +1613,7 @@
 				READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
 			);
 
-		if (IS_PLUTO(sba_dev->iodc)) {
+		if (IS_PLUTO(sba_dev->dev)) {
 			sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);
 		} else {
 			sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
@@ -2067,7 +1877,7 @@
 	/* Read HW Rev First */
 	func_class = READ_REG(sba_addr + SBA_FCLASS);
 
-	if (IS_ASTRO(&dev->id)) {
+	if (IS_ASTRO(dev)) {
 		unsigned long fclass;
 		static char astro_rev[]="Astro ?.?";
 
@@ -2078,11 +1888,11 @@
 		astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
 		version = astro_rev;
 
-	} else if (IS_IKE(&dev->id)) {
+	} else if (IS_IKE(dev)) {
 		static char ike_rev[] = "Ike rev ?";
 		ike_rev[8] = '0' + (char) (func_class & 0xff);
 		version = ike_rev;
-	} else if (IS_PLUTO(&dev->id)) {
+	} else if (IS_PLUTO(dev)) {
 		static char pluto_rev[]="Pluto ?.?";
 		pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4); 
 		pluto_rev[8] = '0' + (char) (func_class & 0x0f); 
@@ -2097,7 +1907,7 @@
 		global_ioc_cnt = count_parisc_driver(&sba_driver);
 
 		/* Astro and Pluto have one IOC per SBA */
-		if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id)))
+		if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev)))
 			global_ioc_cnt *= 2;
 	}
 
@@ -2117,7 +1927,6 @@
 
 	sba_dev->dev = dev;
 	sba_dev->hw_rev = func_class;
-	sba_dev->iodc = &dev->id;
 	sba_dev->name = dev->name;
 	sba_dev->sba_hpa = sba_addr;
 
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index c27e782..3029412 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -52,3 +52,11 @@
 
 	  When in doubt, say N.
 
+config HT_IRQ
+	bool "Interrupts on hypertransport devices"
+	default y
+	depends on X86_LOCAL_APIC && X86_IO_APIC
+	help
+	   This allows native hypertransport devices to use interrupts.
+
+	   If unsure say Y.
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index f2d152b..e3beb78 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -14,6 +14,12 @@
 # Build the PCI Hotplug drivers if we were asked to
 obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
 
+# Build the PCI MSI interrupt support
+obj-$(CONFIG_PCI_MSI) += msi.o
+
+# Build the Hypertransport interrupt support
+obj-$(CONFIG_HT_IRQ) += htirq.o
+
 #
 # Some architectures use the generic PCI setup functions
 #
@@ -27,11 +33,6 @@
 obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
 obj-$(CONFIG_X86_VISWS) += setup-irq.o
 
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
-obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
-
 #
 # ACPI Related PCI FW Functions
 #
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
new file mode 100644
index 0000000..0e27f24
--- /dev/null
+++ b/drivers/pci/htirq.c
@@ -0,0 +1,190 @@
+/*
+ * File:	htirq.c
+ * Purpose:	Hypertransport Interrupt Capability
+ *
+ * Copyright (C) 2006 Linux Networx
+ * Copyright (C) Eric Biederman <ebiederman@lnxi.com>
+ */
+
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/htirq.h>
+
+/* Global ht irq lock.
+ *
+ * This is needed to serialize access to the data port in hypertransport
+ * irq capability.
+ *
+ * With multiple simultaneous hypertransport irq devices it might pay
+ * to make this more fine grained.  But start with simple, stupid, and correct.
+ */
+static DEFINE_SPINLOCK(ht_irq_lock);
+
+struct ht_irq_cfg {
+	struct pci_dev *dev;
+	unsigned pos;
+	unsigned idx;
+};
+
+void write_ht_irq_low(unsigned int irq, u32 data)
+{
+	struct ht_irq_cfg *cfg = get_irq_data(irq);
+	unsigned long flags;
+	spin_lock_irqsave(&ht_irq_lock, flags);
+	pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+	pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+	spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+void write_ht_irq_high(unsigned int irq, u32 data)
+{
+	struct ht_irq_cfg *cfg = get_irq_data(irq);
+	unsigned long flags;
+	spin_lock_irqsave(&ht_irq_lock, flags);
+	pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
+	pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+	spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+u32 read_ht_irq_low(unsigned int irq)
+{
+	struct ht_irq_cfg *cfg = get_irq_data(irq);
+	unsigned long flags;
+	u32 data;
+	spin_lock_irqsave(&ht_irq_lock, flags);
+	pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+	pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+	spin_unlock_irqrestore(&ht_irq_lock, flags);
+	return data;
+}
+
+u32 read_ht_irq_high(unsigned int irq)
+{
+	struct ht_irq_cfg *cfg = get_irq_data(irq);
+	unsigned long flags;
+	u32 data;
+	spin_lock_irqsave(&ht_irq_lock, flags);
+	pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
+	pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+	spin_unlock_irqrestore(&ht_irq_lock, flags);
+	return data;
+}
+
+void mask_ht_irq(unsigned int irq)
+{
+	struct ht_irq_cfg *cfg;
+	unsigned long flags;
+	u32 data;
+
+	cfg = get_irq_data(irq);
+
+	spin_lock_irqsave(&ht_irq_lock, flags);
+	pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+	pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+	data |= 1;
+	pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+	spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+void unmask_ht_irq(unsigned int irq)
+{
+	struct ht_irq_cfg *cfg;
+	unsigned long flags;
+	u32 data;
+
+	cfg = get_irq_data(irq);
+
+	spin_lock_irqsave(&ht_irq_lock, flags);
+	pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+	pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+	data &= ~1;
+	pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+	spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+/**
+ * ht_create_irq - create an irq and attach it to a device.
+ * @dev: The hypertransport device to find the irq capability on.
+ * @idx: Which of the possible irqs to attach to.
+ *
+ * ht_create_irq is needs to be called for all hypertransport devices
+ * that generate irqs.
+ *
+ * The irq number of the new irq or a negative error value is returned.
+ */
+int ht_create_irq(struct pci_dev *dev, int idx)
+{
+	struct ht_irq_cfg *cfg;
+	unsigned long flags;
+	u32 data;
+	int max_irq;
+	int pos;
+	int irq;
+
+	pos = pci_find_capability(dev, PCI_CAP_ID_HT);
+	while (pos) {
+		u8 subtype;
+		pci_read_config_byte(dev, pos + 3, &subtype);
+		if (subtype == HT_CAPTYPE_IRQ)
+			break;
+		pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT);
+	}
+	if (!pos)
+		return -EINVAL;
+
+	/* Verify the idx I want to use is in range */
+	spin_lock_irqsave(&ht_irq_lock, flags);
+	pci_write_config_byte(dev, pos + 2, 1);
+	pci_read_config_dword(dev, pos + 4, &data);
+	spin_unlock_irqrestore(&ht_irq_lock, flags);
+
+	max_irq = (data >> 16) & 0xff;
+	if ( idx > max_irq)
+		return -EINVAL;
+
+	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+	if (!cfg)
+		return -ENOMEM;
+
+	cfg->dev = dev;
+	cfg->pos = pos;
+	cfg->idx = 0x10 + (idx * 2);
+
+	irq = create_irq();
+	if (irq < 0) {
+		kfree(cfg);
+		return -EBUSY;
+	}
+	set_irq_data(irq, cfg);
+
+	if (arch_setup_ht_irq(irq, dev) < 0) {
+		ht_destroy_irq(irq);
+		return -EBUSY;
+	}
+
+	return irq;
+}
+
+/**
+ * ht_destroy_irq - destroy an irq created with ht_create_irq
+ *
+ * This reverses ht_create_irq removing the specified irq from
+ * existence.  The irq should be free before this happens.
+ */
+void ht_destroy_irq(unsigned int irq)
+{
+	struct ht_irq_cfg *cfg;
+
+	cfg = get_irq_data(irq);
+	set_irq_chip(irq, NULL);
+	set_irq_data(irq, NULL);
+	destroy_irq(irq);
+
+	kfree(cfg);
+}
+
+EXPORT_SYMBOL(ht_create_irq);
+EXPORT_SYMBOL(ht_destroy_irq);
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
deleted file mode 100644
index 5ed798b3..0000000
--- a/drivers/pci/msi-apic.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * MSI hooks for standard x86 apic
- */
-
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <asm/smp.h>
-
-#include "msi.h"
-
-/*
- * Shifts for APIC-based data
- */
-
-#define MSI_DATA_VECTOR_SHIFT		0
-#define	    MSI_DATA_VECTOR(v)		(((u8)v) << MSI_DATA_VECTOR_SHIFT)
-
-#define MSI_DATA_DELIVERY_SHIFT		8
-#define     MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_SHIFT)
-#define     MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_SHIFT)
-
-#define MSI_DATA_LEVEL_SHIFT		14
-#define     MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
-#define     MSI_DATA_LEVEL_ASSERT	(1 << MSI_DATA_LEVEL_SHIFT)
-
-#define MSI_DATA_TRIGGER_SHIFT		15
-#define     MSI_DATA_TRIGGER_EDGE	(0 << MSI_DATA_TRIGGER_SHIFT)
-#define     MSI_DATA_TRIGGER_LEVEL	(1 << MSI_DATA_TRIGGER_SHIFT)
-
-/*
- * Shift/mask fields for APIC-based bus address
- */
-
-#define MSI_ADDR_HEADER			0xfee00000
-
-#define MSI_ADDR_DESTID_MASK		0xfff0000f
-#define     MSI_ADDR_DESTID_CPU(cpu)	((cpu) << MSI_TARGET_CPU_SHIFT)
-
-#define MSI_ADDR_DESTMODE_SHIFT		2
-#define     MSI_ADDR_DESTMODE_PHYS	(0 << MSI_ADDR_DESTMODE_SHIFT)
-#define	    MSI_ADDR_DESTMODE_LOGIC	(1 << MSI_ADDR_DESTMODE_SHIFT)
-
-#define MSI_ADDR_REDIRECTION_SHIFT	3
-#define     MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT)
-#define     MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT)
-
-
-static void
-msi_target_apic(unsigned int vector,
-		unsigned int dest_cpu,
-		u32 *address_hi,	/* in/out */
-		u32 *address_lo)	/* in/out */
-{
-	u32 addr = *address_lo;
-
-	addr &= MSI_ADDR_DESTID_MASK;
-	addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
-
-	*address_lo = addr;
-}
-
-static int
-msi_setup_apic(struct pci_dev *pdev,	/* unused in generic */
-		unsigned int vector,
-		u32 *address_hi,
-		u32 *address_lo,
-		u32 *data)
-{
-	unsigned long	dest_phys_id;
-
-	dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
-
-	*address_hi = 0;
-	*address_lo =	MSI_ADDR_HEADER |
-			MSI_ADDR_DESTMODE_PHYS |
-			MSI_ADDR_REDIRECTION_CPU |
-			MSI_ADDR_DESTID_CPU(dest_phys_id);
-
-	*data = MSI_DATA_TRIGGER_EDGE |
-		MSI_DATA_LEVEL_ASSERT |
-		MSI_DATA_DELIVERY_FIXED |
-		MSI_DATA_VECTOR(vector);
-
-	return 0;
-}
-
-static void
-msi_teardown_apic(unsigned int vector)
-{
-	return;		/* no-op */
-}
-
-/*
- * Generic ops used on most IA archs/platforms.  Set with msi_register()
- */
-
-struct msi_ops msi_apic_ops = {
-	.setup = msi_setup_apic,
-	.teardown = msi_teardown_apic,
-	.target = msi_target_apic,
-};
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 27a0574..f9fdc54 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -6,6 +6,7 @@
  * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
  */
 
+#include <linux/err.h>
 #include <linux/mm.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
@@ -14,6 +15,7 @@
 #include <linux/smp_lock.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
+#include <linux/msi.h>
 
 #include <asm/errno.h>
 #include <asm/io.h>
@@ -27,23 +29,6 @@
 static kmem_cache_t* msi_cachep;
 
 static int pci_msi_enable = 1;
-static int last_alloc_vector;
-static int nr_released_vectors;
-static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
-static int nr_msix_devices;
-
-#ifndef CONFIG_X86_IO_APIC
-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-#endif
-
-static struct msi_ops *msi_ops;
-
-int
-msi_register(struct msi_ops *ops)
-{
-	msi_ops = ops;
-	return 0;
-}
 
 static int msi_cache_init(void)
 {
@@ -55,26 +40,25 @@
 	return 0;
 }
 
-static void msi_set_mask_bit(unsigned int vector, int flag)
+static void msi_set_mask_bit(unsigned int irq, int flag)
 {
 	struct msi_desc *entry;
 
-	entry = (struct msi_desc *)msi_desc[vector];
-	if (!entry || !entry->dev || !entry->mask_base)
-		return;
+	entry = msi_desc[irq];
+	BUG_ON(!entry || !entry->dev);
 	switch (entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
-	{
-		int		pos;
-		u32		mask_bits;
+		if (entry->msi_attrib.maskbit) {
+			int		pos;
+			u32		mask_bits;
 
-		pos = (long)entry->mask_base;
-		pci_read_config_dword(entry->dev, pos, &mask_bits);
-		mask_bits &= ~(1);
-		mask_bits |= flag;
-		pci_write_config_dword(entry->dev, pos, mask_bits);
+			pos = (long)entry->mask_base;
+			pci_read_config_dword(entry->dev, pos, &mask_bits);
+			mask_bits &= ~(1);
+			mask_bits |= flag;
+			pci_write_config_dword(entry->dev, pos, mask_bits);
+		}
 		break;
-	}
 	case PCI_CAP_ID_MSIX:
 	{
 		int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -83,261 +67,101 @@
 		break;
 	}
 	default:
+		BUG();
 		break;
 	}
 }
 
-#ifdef CONFIG_SMP
-static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
+void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-	struct msi_desc *entry;
-	u32 address_hi, address_lo;
-	unsigned int irq = vector;
-	unsigned int dest_cpu = first_cpu(cpu_mask);
-
-	entry = (struct msi_desc *)msi_desc[vector];
-	if (!entry || !entry->dev)
-		return;
-
-	switch (entry->msi_attrib.type) {
+	struct msi_desc *entry = get_irq_data(irq);
+	switch(entry->msi_attrib.type) {
 	case PCI_CAP_ID_MSI:
 	{
-		int pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI);
+		struct pci_dev *dev = entry->dev;
+		int pos = entry->msi_attrib.pos;
+		u16 data;
 
-		if (!pos)
-			return;
-
-		pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
-			&address_hi);
-		pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
-			&address_lo);
-
-		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
-
-		pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
-			address_hi);
-		pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
-			address_lo);
-		set_native_irq_info(irq, cpu_mask);
+		pci_read_config_dword(dev, msi_lower_address_reg(pos),
+					&msg->address_lo);
+		if (entry->msi_attrib.is_64) {
+			pci_read_config_dword(dev, msi_upper_address_reg(pos),
+						&msg->address_hi);
+			pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+		} else {
+			msg->address_hi = 0;
+			pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+		}
+		msg->data = data;
 		break;
 	}
 	case PCI_CAP_ID_MSIX:
 	{
-		int offset_hi =
-			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
-		int offset_lo =
-			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
+		void __iomem *base;
+		base = entry->mask_base +
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
 
-		address_hi = readl(entry->mask_base + offset_hi);
-		address_lo = readl(entry->mask_base + offset_lo);
+		msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+		msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+		msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
+ 		break;
+ 	}
+ 	default:
+		BUG();
+	}
+}
 
-		msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+void write_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+	struct msi_desc *entry = get_irq_data(irq);
+	switch (entry->msi_attrib.type) {
+	case PCI_CAP_ID_MSI:
+	{
+		struct pci_dev *dev = entry->dev;
+		int pos = entry->msi_attrib.pos;
 
-		writel(address_hi, entry->mask_base + offset_hi);
-		writel(address_lo, entry->mask_base + offset_lo);
-		set_native_irq_info(irq, cpu_mask);
+		pci_write_config_dword(dev, msi_lower_address_reg(pos),
+					msg->address_lo);
+		if (entry->msi_attrib.is_64) {
+			pci_write_config_dword(dev, msi_upper_address_reg(pos),
+						msg->address_hi);
+			pci_write_config_word(dev, msi_data_reg(pos, 1),
+						msg->data);
+		} else {
+			pci_write_config_word(dev, msi_data_reg(pos, 0),
+						msg->data);
+		}
+		break;
+	}
+	case PCI_CAP_ID_MSIX:
+	{
+		void __iomem *base;
+		base = entry->mask_base +
+			entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+		writel(msg->address_lo,
+			base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+		writel(msg->address_hi,
+			base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+		writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
 		break;
 	}
 	default:
-		break;
+		BUG();
 	}
 }
-#else
-#define set_msi_affinity NULL
-#endif /* CONFIG_SMP */
 
-static void mask_MSI_irq(unsigned int vector)
+void mask_msi_irq(unsigned int irq)
 {
-	msi_set_mask_bit(vector, 1);
+	msi_set_mask_bit(irq, 1);
 }
 
-static void unmask_MSI_irq(unsigned int vector)
+void unmask_msi_irq(unsigned int irq)
 {
-	msi_set_mask_bit(vector, 0);
+	msi_set_mask_bit(irq, 0);
 }
 
-static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
-{
-	struct msi_desc *entry;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msi_lock, flags);
-	entry = msi_desc[vector];
-	if (!entry || !entry->dev) {
-		spin_unlock_irqrestore(&msi_lock, flags);
-		return 0;
-	}
-	entry->msi_attrib.state = 1;	/* Mark it active */
-	spin_unlock_irqrestore(&msi_lock, flags);
-
-	return 0;	/* never anything pending */
-}
-
-static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
-{
-	startup_msi_irq_wo_maskbit(vector);
-	unmask_MSI_irq(vector);
-	return 0;	/* never anything pending */
-}
-
-static void shutdown_msi_irq(unsigned int vector)
-{
-	struct msi_desc *entry;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msi_lock, flags);
-	entry = msi_desc[vector];
-	if (entry && entry->dev)
-		entry->msi_attrib.state = 0;	/* Mark it not active */
-	spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static void end_msi_irq_wo_maskbit(unsigned int vector)
-{
-	move_native_irq(vector);
-	ack_APIC_irq();
-}
-
-static void end_msi_irq_w_maskbit(unsigned int vector)
-{
-	move_native_irq(vector);
-	unmask_MSI_irq(vector);
-	ack_APIC_irq();
-}
-
-static void do_nothing(unsigned int vector)
-{
-}
-
-/*
- * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI-X Capability Structure.
- */
-static struct hw_interrupt_type msix_irq_type = {
-	.typename	= "PCI-MSI-X",
-	.startup	= startup_msi_irq_w_maskbit,
-	.shutdown	= shutdown_msi_irq,
-	.enable		= unmask_MSI_irq,
-	.disable	= mask_MSI_irq,
-	.ack		= mask_MSI_irq,
-	.end		= end_msi_irq_w_maskbit,
-	.set_affinity	= set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure with
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_w_maskbit_type = {
-	.typename	= "PCI-MSI",
-	.startup	= startup_msi_irq_w_maskbit,
-	.shutdown	= shutdown_msi_irq,
-	.enable		= unmask_MSI_irq,
-	.disable	= mask_MSI_irq,
-	.ack		= mask_MSI_irq,
-	.end		= end_msi_irq_w_maskbit,
-	.set_affinity	= set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure without
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
-	.typename	= "PCI-MSI",
-	.startup	= startup_msi_irq_wo_maskbit,
-	.shutdown	= shutdown_msi_irq,
-	.enable		= do_nothing,
-	.disable	= do_nothing,
-	.ack		= do_nothing,
-	.end		= end_msi_irq_wo_maskbit,
-	.set_affinity	= set_msi_affinity
-};
-
-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
-static int assign_msi_vector(void)
-{
-	static int new_vector_avail = 1;
-	int vector;
-	unsigned long flags;
-
-	/*
-	 * msi_lock is provided to ensure that successful allocation of MSI
-	 * vector is assigned unique among drivers.
-	 */
-	spin_lock_irqsave(&msi_lock, flags);
-
-	if (!new_vector_avail) {
-		int free_vector = 0;
-
-		/*
-	 	 * vector_irq[] = -1 indicates that this specific vector is:
-	 	 * - assigned for MSI (since MSI have no associated IRQ) or
-	 	 * - assigned for legacy if less than 16, or
-	 	 * - having no corresponding 1:1 vector-to-IOxAPIC IRQ mapping
-	 	 * vector_irq[] = 0 indicates that this vector, previously
-		 * assigned for MSI, is freed by hotplug removed operations.
-		 * This vector will be reused for any subsequent hotplug added
-		 * operations.
-	 	 * vector_irq[] > 0 indicates that this vector is assigned for
-		 * IOxAPIC IRQs. This vector and its value provides a 1-to-1
-		 * vector-to-IOxAPIC IRQ mapping.
-	 	 */
-		for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
-			if (vector_irq[vector] != 0)
-				continue;
-			free_vector = vector;
-			if (!msi_desc[vector])
-			      	break;
-			else
-				continue;
-		}
-		if (!free_vector) {
-			spin_unlock_irqrestore(&msi_lock, flags);
-			return -EBUSY;
-		}
-		vector_irq[free_vector] = -1;
-		nr_released_vectors--;
-		spin_unlock_irqrestore(&msi_lock, flags);
-		if (msi_desc[free_vector] != NULL) {
-			struct pci_dev *dev;
-			int tail;
-
-			/* free all linked vectors before re-assign */
-			do {
-				spin_lock_irqsave(&msi_lock, flags);
-				dev = msi_desc[free_vector]->dev;
-				tail = msi_desc[free_vector]->link.tail;
-				spin_unlock_irqrestore(&msi_lock, flags);
-				msi_free_vector(dev, tail, 1);
-			} while (free_vector != tail);
-		}
-
-		return free_vector;
-	}
-	vector = assign_irq_vector(AUTO_ASSIGN);
-	last_alloc_vector = vector;
-	if (vector  == LAST_DEVICE_VECTOR)
-		new_vector_avail = 0;
-
-	spin_unlock_irqrestore(&msi_lock, flags);
-	return vector;
-}
-
-static int get_new_vector(void)
-{
-	int vector = assign_msi_vector();
-
-	if (vector > 0)
-		set_intr_gate(vector, interrupt[vector]);
-
-	return vector;
-}
-
+static int msi_free_irq(struct pci_dev* dev, int irq);
 static int msi_init(void)
 {
 	static int status = -ENOMEM;
@@ -352,22 +176,6 @@
 		return status;
 	}
 
-	status = msi_arch_init();
-	if (status < 0) {
-		pci_msi_enable = 0;
-		printk(KERN_WARNING
-		       "PCI: MSI arch init failed.  MSI disabled.\n");
-		return status;
-	}
-
-	if (! msi_ops) {
-		printk(KERN_WARNING
-		       "PCI: MSI ops not registered. MSI disabled.\n");
-		status = -EINVAL;
-		return status;
-	}
-
-	last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
 	status = msi_cache_init();
 	if (status < 0) {
 		pci_msi_enable = 0;
@@ -375,23 +183,9 @@
 		return status;
 	}
 
-	if (last_alloc_vector < 0) {
-		pci_msi_enable = 0;
-		printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
-		status = -EBUSY;
-		return status;
-	}
-	vector_irq[last_alloc_vector] = 0;
-	nr_released_vectors++;
-
 	return status;
 }
 
-static int get_msi_vector(struct pci_dev *dev)
-{
-	return get_new_vector();
-}
-
 static struct msi_desc* alloc_msi_entry(void)
 {
 	struct msi_desc *entry;
@@ -406,29 +200,44 @@
 	return entry;
 }
 
-static void attach_msi_entry(struct msi_desc *entry, int vector)
+static void attach_msi_entry(struct msi_desc *entry, int irq)
 {
 	unsigned long flags;
 
 	spin_lock_irqsave(&msi_lock, flags);
-	msi_desc[vector] = entry;
+	msi_desc[irq] = entry;
 	spin_unlock_irqrestore(&msi_lock, flags);
 }
 
-static void irq_handler_init(int cap_id, int pos, int mask)
+static int create_msi_irq(void)
 {
-	unsigned long flags;
+	struct msi_desc *entry;
+	int irq;
 
-	spin_lock_irqsave(&irq_desc[pos].lock, flags);
-	if (cap_id == PCI_CAP_ID_MSIX)
-		irq_desc[pos].chip = &msix_irq_type;
-	else {
-		if (!mask)
-			irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
-		else
-			irq_desc[pos].chip = &msi_irq_w_maskbit_type;
+	entry = alloc_msi_entry();
+	if (!entry)
+		return -ENOMEM;
+
+	irq = create_irq();
+	if (irq < 0) {
+		kmem_cache_free(msi_cachep, entry);
+		return -EBUSY;
 	}
-	spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
+
+	set_irq_data(irq, entry);
+
+	return irq;
+}
+
+static void destroy_msi_irq(unsigned int irq)
+{
+	struct msi_desc *entry;
+
+	entry = get_irq_data(irq);
+	set_irq_chip(irq, NULL);
+	set_irq_data(irq, NULL);
+	destroy_irq(irq);
+	kmem_cache_free(msi_cachep, entry);
 }
 
 static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
@@ -473,21 +282,21 @@
 	}
 }
 
-static int msi_lookup_vector(struct pci_dev *dev, int type)
+static int msi_lookup_irq(struct pci_dev *dev, int type)
 {
-	int vector;
+	int irq;
 	unsigned long flags;
 
 	spin_lock_irqsave(&msi_lock, flags);
-	for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
-		if (!msi_desc[vector] || msi_desc[vector]->dev != dev ||
-			msi_desc[vector]->msi_attrib.type != type ||
-			msi_desc[vector]->msi_attrib.default_vector != dev->irq)
+	for (irq = 0; irq < NR_IRQS; irq++) {
+		if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
+			msi_desc[irq]->msi_attrib.type != type ||
+			msi_desc[irq]->msi_attrib.default_irq != dev->irq)
 			continue;
 		spin_unlock_irqrestore(&msi_lock, flags);
-		/* This pre-assigned MSI vector for this device
-		   already exits. Override dev->irq with this vector */
-		dev->irq = vector;
+		/* This pre-assigned MSI irq for this device
+		   already exits. Override dev->irq with this irq */
+		dev->irq = irq;
 		return 0;
 	}
 	spin_unlock_irqrestore(&msi_lock, flags);
@@ -499,11 +308,6 @@
 {
 	if (!dev)
 		return;
-
-   	if (pci_find_capability(dev, PCI_CAP_ID_MSIX) > 0)
-		nr_msix_devices++;
-	else if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0)
-		nr_reserved_vectors++;
 }
 
 #ifdef CONFIG_PM
@@ -577,7 +381,7 @@
 {
 	int pos;
 	int temp;
-	int vector, head, tail = 0;
+	int irq, head, tail = 0;
 	u16 control;
 	struct pci_cap_saved_state *save_state;
 
@@ -599,33 +403,20 @@
 
 	/* save the table */
 	temp = dev->irq;
-	if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+	if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
 		kfree(save_state);
 		return -EINVAL;
 	}
 
-	vector = head = dev->irq;
+	irq = head = dev->irq;
 	while (head != tail) {
-		int j;
-		void __iomem *base;
 		struct msi_desc *entry;
 
-		entry = msi_desc[vector];
-		base = entry->mask_base;
-		j = entry->msi_attrib.entry_nr;
+		entry = msi_desc[irq];
+		read_msi_msg(irq, &entry->msg_save);
 
-		entry->address_lo_save =
-			readl(base + j * PCI_MSIX_ENTRY_SIZE +
-			      PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		entry->address_hi_save =
-			readl(base + j * PCI_MSIX_ENTRY_SIZE +
-			      PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		entry->data_save =
-			readl(base + j * PCI_MSIX_ENTRY_SIZE +
-			      PCI_MSIX_ENTRY_DATA_OFFSET);
-
-		tail = msi_desc[vector]->link.tail;
-		vector = tail;
+		tail = msi_desc[irq]->link.tail;
+		irq = tail;
 	}
 	dev->irq = temp;
 
@@ -638,9 +429,7 @@
 {
 	u16 save;
 	int pos;
-	int vector, head, tail = 0;
-	void __iomem *base;
-	int j;
+	int irq, head, tail = 0;
 	struct msi_desc *entry;
 	int temp;
 	struct pci_cap_saved_state *save_state;
@@ -658,26 +447,15 @@
 
 	/* route the table */
 	temp = dev->irq;
-	if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX))
+	if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
 		return;
-	vector = head = dev->irq;
+	irq = head = dev->irq;
 	while (head != tail) {
-		entry = msi_desc[vector];
-		base = entry->mask_base;
-		j = entry->msi_attrib.entry_nr;
+		entry = msi_desc[irq];
+		write_msi_msg(irq, &entry->msg_save);
 
-		writel(entry->address_lo_save,
-			base + j * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(entry->address_hi_save,
-			base + j * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(entry->data_save,
-			base + j * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_DATA_OFFSET);
-
-		tail = msi_desc[vector]->link.tail;
-		vector = tail;
+		tail = msi_desc[irq]->link.tail;
+		irq = tail;
 	}
 	dev->irq = temp;
 
@@ -686,32 +464,43 @@
 }
 #endif
 
-static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
+/**
+ * msi_capability_init - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device function with a single
+ * MSI irq, regardless of device function is capable of handling
+ * multiple messages. A return of zero indicates the successful setup
+ * of an entry zero with the new MSI irq or non-zero for otherwise.
+ **/
+static int msi_capability_init(struct pci_dev *dev)
 {
 	int status;
-	u32 address_hi;
-	u32 address_lo;
-	u32 data;
-	int pos, vector = dev->irq;
+	struct msi_desc *entry;
+	int pos, irq;
 	u16 control;
 
    	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
 	pci_read_config_word(dev, msi_control_reg(pos), &control);
+	/* MSI Entry Initialization */
+	irq = create_msi_irq();
+	if (irq < 0)
+		return irq;
 
-	/* Configure MSI capability structure */
-	status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data);
-	if (status < 0)
-		return status;
-
-	pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
-	if (is_64bit_address(control)) {
-		pci_write_config_dword(dev,
-			msi_upper_address_reg(pos), address_hi);
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 1), data);
-	} else
-		pci_write_config_word(dev,
-			msi_data_reg(pos, 0), data);
+	entry = get_irq_data(irq);
+	entry->link.head = irq;
+	entry->link.tail = irq;
+	entry->msi_attrib.type = PCI_CAP_ID_MSI;
+	entry->msi_attrib.is_64 = is_64bit_address(control);
+	entry->msi_attrib.entry_nr = 0;
+	entry->msi_attrib.maskbit = is_mask_bit_support(control);
+	entry->msi_attrib.default_irq = dev->irq;	/* Save IOAPIC IRQ */
+	entry->msi_attrib.pos = pos;
+	if (is_mask_bit_support(control)) {
+		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
+				is_64bit_address(control));
+	}
+	entry->dev = dev;
 	if (entry->msi_attrib.maskbit) {
 		unsigned int maskbits, temp;
 		/* All MSIs are unmasked by default, Mask them all */
@@ -725,65 +514,18 @@
 			msi_mask_bits_reg(pos, is_64bit_address(control)),
 			maskbits);
 	}
-
-	return 0;
-}
-
-/**
- * msi_capability_init - configure device's MSI capability structure
- * @dev: pointer to the pci_dev data structure of MSI device function
- *
- * Setup the MSI capability structure of device function with a single
- * MSI vector, regardless of device function is capable of handling
- * multiple messages. A return of zero indicates the successful setup
- * of an entry zero with the new MSI vector or non-zero for otherwise.
- **/
-static int msi_capability_init(struct pci_dev *dev)
-{
-	int status;
-	struct msi_desc *entry;
-	int pos, vector;
-	u16 control;
-
-   	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-	pci_read_config_word(dev, msi_control_reg(pos), &control);
-	/* MSI Entry Initialization */
-	entry = alloc_msi_entry();
-	if (!entry)
-		return -ENOMEM;
-
-	vector = get_msi_vector(dev);
-	if (vector < 0) {
-		kmem_cache_free(msi_cachep, entry);
-		return -EBUSY;
-	}
-	entry->link.head = vector;
-	entry->link.tail = vector;
-	entry->msi_attrib.type = PCI_CAP_ID_MSI;
-	entry->msi_attrib.state = 0;			/* Mark it not active */
-	entry->msi_attrib.entry_nr = 0;
-	entry->msi_attrib.maskbit = is_mask_bit_support(control);
-	entry->msi_attrib.default_vector = dev->irq;	/* Save IOAPIC IRQ */
-	dev->irq = vector;
-	entry->dev = dev;
-	if (is_mask_bit_support(control)) {
-		entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
-				is_64bit_address(control));
-	}
-	/* Replace with MSI handler */
-	irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
 	/* Configure MSI capability structure */
-	status = msi_register_init(dev, entry);
-	if (status != 0) {
-		dev->irq = entry->msi_attrib.default_vector;
-		kmem_cache_free(msi_cachep, entry);
+	status = arch_setup_msi_irq(irq, dev);
+	if (status < 0) {
+		destroy_msi_irq(irq);
 		return status;
 	}
 
-	attach_msi_entry(entry, vector);
+	attach_msi_entry(entry, irq);
 	/* Set MSI enabled bits	 */
 	enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
 
+	dev->irq = irq;
 	return 0;
 }
 
@@ -794,18 +536,15 @@
  * @nvec: number of @entries
  *
  * Setup the MSI-X capability structure of device function with a
- * single MSI-X vector. A return of zero indicates the successful setup of
- * requested MSI-X entries with allocated vectors or non-zero for otherwise.
+ * single MSI-X irq. A return of zero indicates the successful setup of
+ * requested MSI-X entries with allocated irqs or non-zero for otherwise.
  **/
 static int msix_capability_init(struct pci_dev *dev,
 				struct msix_entry *entries, int nvec)
 {
 	struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-	u32 address_hi;
-	u32 address_lo;
-	u32 data;
 	int status;
-	int vector, pos, i, j, nr_entries, temp = 0;
+	int irq, pos, i, j, nr_entries, temp = 0;
 	unsigned long phys_addr;
 	u32 table_offset;
  	u16 control;
@@ -827,65 +566,56 @@
 
 	/* MSI-X Table Initialization */
 	for (i = 0; i < nvec; i++) {
-		entry = alloc_msi_entry();
-		if (!entry)
+		irq = create_msi_irq();
+		if (irq < 0)
 			break;
-		vector = get_msi_vector(dev);
-		if (vector < 0) {
-			kmem_cache_free(msi_cachep, entry);
-			break;
-		}
 
+		entry = get_irq_data(irq);
  		j = entries[i].entry;
- 		entries[i].vector = vector;
+ 		entries[i].vector = irq;
 		entry->msi_attrib.type = PCI_CAP_ID_MSIX;
- 		entry->msi_attrib.state = 0;		/* Mark it not active */
+		entry->msi_attrib.is_64 = 1;
 		entry->msi_attrib.entry_nr = j;
 		entry->msi_attrib.maskbit = 1;
-		entry->msi_attrib.default_vector = dev->irq;
+		entry->msi_attrib.default_irq = dev->irq;
+		entry->msi_attrib.pos = pos;
 		entry->dev = dev;
 		entry->mask_base = base;
 		if (!head) {
-			entry->link.head = vector;
-			entry->link.tail = vector;
+			entry->link.head = irq;
+			entry->link.tail = irq;
 			head = entry;
 		} else {
 			entry->link.head = temp;
 			entry->link.tail = tail->link.tail;
-			tail->link.tail = vector;
-			head->link.head = vector;
+			tail->link.tail = irq;
+			head->link.head = irq;
 		}
-		temp = vector;
+		temp = irq;
 		tail = entry;
-		/* Replace with MSI-X handler */
-		irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
 		/* Configure MSI-X capability structure */
-		status = msi_ops->setup(dev, vector,
-					&address_hi,
-					&address_lo,
-					&data);
-		if (status < 0)
+		status = arch_setup_msi_irq(irq, dev);
+		if (status < 0) {
+			destroy_msi_irq(irq);
 			break;
+		}
 
-		writel(address_lo,
-			base + j * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-		writel(address_hi,
-			base + j * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-		writel(data,
-			base + j * PCI_MSIX_ENTRY_SIZE +
-			PCI_MSIX_ENTRY_DATA_OFFSET);
-		attach_msi_entry(entry, vector);
+		attach_msi_entry(entry, irq);
 	}
 	if (i != nvec) {
+		int avail = i - 1;
 		i--;
 		for (; i >= 0; i--) {
-			vector = (entries + i)->vector;
-			msi_free_vector(dev, vector, 0);
+			irq = (entries + i)->vector;
+			msi_free_irq(dev, irq);
 			(entries + i)->vector = 0;
 		}
-		return -EBUSY;
+		/* If we had some success report the number of irqs
+		 * we succeeded in setting up.
+		 */
+		if (avail <= 0)
+			avail = -EBUSY;
+		return avail;
 	}
 	/* Set MSI-X enabled bits */
 	enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -925,15 +655,14 @@
  * @dev: pointer to the pci_dev data structure of MSI device function
  *
  * Setup the MSI capability structure of device function with
- * a single MSI vector upon its software driver call to request for
+ * a single MSI irq upon its software driver call to request for
  * MSI mode enabled on its hardware device function. A return of zero
  * indicates the successful setup of an entry zero with the new MSI
- * vector or non-zero for otherwise.
+ * irq or non-zero for otherwise.
  **/
 int pci_enable_msi(struct pci_dev* dev)
 {
 	int pos, temp, status;
-	u16 control;
 
 	if (pci_msi_supported(dev) < 0)
 		return -EINVAL;
@@ -948,52 +677,25 @@
 	if (!pos)
 		return -EINVAL;
 
-	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
-		/* Lookup Sucess */
-		unsigned long flags;
+	WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
 
-		pci_read_config_word(dev, msi_control_reg(pos), &control);
-		if (control & PCI_MSI_FLAGS_ENABLE)
-			return 0;	/* Already in MSI mode */
-		spin_lock_irqsave(&msi_lock, flags);
-		if (!vector_irq[dev->irq]) {
-			msi_desc[dev->irq]->msi_attrib.state = 0;
-			vector_irq[dev->irq] = -1;
-			nr_released_vectors--;
-			spin_unlock_irqrestore(&msi_lock, flags);
-			status = msi_register_init(dev, msi_desc[dev->irq]);
-			if (status == 0)
-				enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
-			return status;
-		}
-		spin_unlock_irqrestore(&msi_lock, flags);
-		dev->irq = temp;
-	}
-	/* Check whether driver already requested for MSI-X vectors */
+	/* Check whether driver already requested for MSI-X irqs */
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-	if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+	if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
 			printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
-			       "Device already has MSI-X vectors assigned\n",
+			       "Device already has MSI-X irq assigned\n",
 			       pci_name(dev));
 			dev->irq = temp;
 			return -EINVAL;
 	}
 	status = msi_capability_init(dev);
-	if (!status) {
-   		if (!pos)
-			nr_reserved_vectors--;	/* Only MSI capable */
-		else if (nr_msix_devices > 0)
-			nr_msix_devices--;	/* Both MSI and MSI-X capable,
-						   but choose enabling MSI */
-	}
-
 	return status;
 }
 
 void pci_disable_msi(struct pci_dev* dev)
 {
 	struct msi_desc *entry;
-	int pos, default_vector;
+	int pos, default_irq;
 	u16 control;
 	unsigned long flags;
 
@@ -1010,41 +712,41 @@
 	if (!(control & PCI_MSI_FLAGS_ENABLE))
 		return;
 
+	disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+
 	spin_lock_irqsave(&msi_lock, flags);
 	entry = msi_desc[dev->irq];
 	if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
 		spin_unlock_irqrestore(&msi_lock, flags);
 		return;
 	}
-	if (entry->msi_attrib.state) {
+	if (irq_has_action(dev->irq)) {
 		spin_unlock_irqrestore(&msi_lock, flags);
 		printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
-		       "free_irq() on MSI vector %d\n",
+		       "free_irq() on MSI irq %d\n",
 		       pci_name(dev), dev->irq);
-		BUG_ON(entry->msi_attrib.state > 0);
+		BUG_ON(irq_has_action(dev->irq));
 	} else {
-		vector_irq[dev->irq] = 0; /* free it */
-		nr_released_vectors++;
-		default_vector = entry->msi_attrib.default_vector;
+		default_irq = entry->msi_attrib.default_irq;
 		spin_unlock_irqrestore(&msi_lock, flags);
-		/* Restore dev->irq to its default pin-assertion vector */
-		dev->irq = default_vector;
-		disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
-					PCI_CAP_ID_MSI);
+		msi_free_irq(dev, dev->irq);
+
+		/* Restore dev->irq to its default pin-assertion irq */
+		dev->irq = default_irq;
 	}
 }
 
-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
+static int msi_free_irq(struct pci_dev* dev, int irq)
 {
 	struct msi_desc *entry;
 	int head, entry_nr, type;
 	void __iomem *base;
 	unsigned long flags;
 
-	msi_ops->teardown(vector);
+	arch_teardown_msi_irq(irq);
 
 	spin_lock_irqsave(&msi_lock, flags);
-	entry = msi_desc[vector];
+	entry = msi_desc[irq];
 	if (!entry || entry->dev != dev) {
 		spin_unlock_irqrestore(&msi_lock, flags);
 		return -EINVAL;
@@ -1056,100 +758,42 @@
 	msi_desc[entry->link.head]->link.tail = entry->link.tail;
 	msi_desc[entry->link.tail]->link.head = entry->link.head;
 	entry->dev = NULL;
-	if (!reassign) {
-		vector_irq[vector] = 0;
-		nr_released_vectors++;
-	}
-	msi_desc[vector] = NULL;
+	msi_desc[irq] = NULL;
 	spin_unlock_irqrestore(&msi_lock, flags);
 
-	kmem_cache_free(msi_cachep, entry);
+	destroy_msi_irq(irq);
 
 	if (type == PCI_CAP_ID_MSIX) {
-		if (!reassign)
-			writel(1, base +
-				entry_nr * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+		writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
+			PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
 
-		if (head == vector)
+		if (head == irq)
 			iounmap(base);
 	}
 
 	return 0;
 }
 
-static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
-{
-	int vector = head, tail = 0;
-	int i, j = 0, nr_entries = 0;
-	void __iomem *base;
-	unsigned long flags;
-
-	spin_lock_irqsave(&msi_lock, flags);
-	while (head != tail) {
-		nr_entries++;
-		tail = msi_desc[vector]->link.tail;
-		if (entries[0].entry == msi_desc[vector]->msi_attrib.entry_nr)
-			j = vector;
-		vector = tail;
-	}
-	if (*nvec > nr_entries) {
-		spin_unlock_irqrestore(&msi_lock, flags);
-		*nvec = nr_entries;
-		return -EINVAL;
-	}
-	vector = ((j > 0) ? j : head);
-	for (i = 0; i < *nvec; i++) {
-		j = msi_desc[vector]->msi_attrib.entry_nr;
-		msi_desc[vector]->msi_attrib.state = 0;	/* Mark it not active */
-		vector_irq[vector] = -1;		/* Mark it busy */
-		nr_released_vectors--;
-		entries[i].vector = vector;
-		if (j != (entries + i)->entry) {
-			base = msi_desc[vector]->mask_base;
-			msi_desc[vector]->msi_attrib.entry_nr =
-				(entries + i)->entry;
-			writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET), base +
-				(entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
-			writel(	readl(base + j * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET), base +
-				(entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
-			writel( (readl(base + j * PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_DATA_OFFSET) & 0xff00) | vector,
-				base + (entries+i)->entry*PCI_MSIX_ENTRY_SIZE +
-				PCI_MSIX_ENTRY_DATA_OFFSET);
-		}
-		vector = msi_desc[vector]->link.tail;
-	}
-	spin_unlock_irqrestore(&msi_lock, flags);
-
-	return 0;
-}
-
 /**
  * pci_enable_msix - configure device's MSI-X capability structure
  * @dev: pointer to the pci_dev data structure of MSI-X device function
  * @entries: pointer to an array of MSI-X entries
- * @nvec: number of MSI-X vectors requested for allocation by device driver
+ * @nvec: number of MSI-X irqs requested for allocation by device driver
  *
  * Setup the MSI-X capability structure of device function with the number
- * of requested vectors upon its software driver call to request for
+ * of requested irqs upon its software driver call to request for
  * MSI-X mode enabled on its hardware device function. A return of zero
  * indicates the successful configuration of MSI-X capability structure
- * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
+ * with new allocated MSI-X irqs. A return of < 0 indicates a failure.
  * Or a return of > 0 indicates that driver request is exceeding the number
- * of vectors available. Driver should use the returned value to re-send
+ * of irqs available. Driver should use the returned value to re-send
  * its request.
  **/
 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 {
-	int status, pos, nr_entries, free_vectors;
+	int status, pos, nr_entries;
 	int i, j, temp;
 	u16 control;
-	unsigned long flags;
 
 	if (!entries || pci_msi_supported(dev) < 0)
  		return -EINVAL;
@@ -1163,9 +807,6 @@
  		return -EINVAL;
 
 	pci_read_config_word(dev, msi_control_reg(pos), &control);
-	if (control & PCI_MSIX_FLAGS_ENABLE)
-		return -EINVAL;			/* Already in MSI-X mode */
-
 	nr_entries = multi_msix_capable(control);
 	if (nvec > nr_entries)
 		return -EINVAL;
@@ -1180,56 +821,18 @@
 		}
 	}
 	temp = dev->irq;
-	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
-		/* Lookup Sucess */
-		nr_entries = nvec;
-		/* Reroute MSI-X table */
-		if (reroute_msix_table(dev->irq, entries, &nr_entries)) {
-			/* #requested > #previous-assigned */
-			dev->irq = temp;
-			return nr_entries;
-		}
-		dev->irq = temp;
-		enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
-		return 0;
-	}
-	/* Check whether driver already requested for MSI vector */
+	WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+
+	/* Check whether driver already requested for MSI irq */
    	if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
-		!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+		!msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
 		printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
-		       "Device already has an MSI vector assigned\n",
+		       "Device already has an MSI irq assigned\n",
 		       pci_name(dev));
 		dev->irq = temp;
 		return -EINVAL;
 	}
-
-	spin_lock_irqsave(&msi_lock, flags);
-	/*
-	 * msi_lock is provided to ensure that enough vectors resources are
-	 * available before granting.
-	 */
-	free_vectors = pci_vector_resources(last_alloc_vector,
-				nr_released_vectors);
-	/* Ensure that each MSI/MSI-X device has one vector reserved by
-	   default to avoid any MSI-X driver to take all available
- 	   resources */
-	free_vectors -= nr_reserved_vectors;
-	/* Find the average of free vectors among MSI-X devices */
-	if (nr_msix_devices > 0)
-		free_vectors /= nr_msix_devices;
-	spin_unlock_irqrestore(&msi_lock, flags);
-
-	if (nvec > free_vectors) {
-		if (free_vectors > 0)
-			return free_vectors;
-		else
-			return -EBUSY;
-	}
-
 	status = msix_capability_init(dev, entries, nvec);
-	if (!status && nr_msix_devices > 0)
-		nr_msix_devices--;
-
 	return status;
 }
 
@@ -1251,53 +854,47 @@
 	if (!(control & PCI_MSIX_FLAGS_ENABLE))
 		return;
 
+	disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+
 	temp = dev->irq;
-	if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
-		int state, vector, head, tail = 0, warning = 0;
+	if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+		int irq, head, tail = 0, warning = 0;
 		unsigned long flags;
 
-		vector = head = dev->irq;
-		spin_lock_irqsave(&msi_lock, flags);
+		irq = head = dev->irq;
+		dev->irq = temp;			/* Restore pin IRQ */
 		while (head != tail) {
-			state = msi_desc[vector]->msi_attrib.state;
-			if (state)
+			spin_lock_irqsave(&msi_lock, flags);
+			tail = msi_desc[irq]->link.tail;
+			spin_unlock_irqrestore(&msi_lock, flags);
+			if (irq_has_action(irq))
 				warning = 1;
-			else {
-				vector_irq[vector] = 0; /* free it */
-				nr_released_vectors++;
-			}
-			tail = msi_desc[vector]->link.tail;
-			vector = tail;
+			else if (irq != head)	/* Release MSI-X irq */
+				msi_free_irq(dev, irq);
+			irq = tail;
 		}
-		spin_unlock_irqrestore(&msi_lock, flags);
+		msi_free_irq(dev, irq);
 		if (warning) {
-			dev->irq = temp;
 			printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
-			       "free_irq() on all MSI-X vectors\n",
+			       "free_irq() on all MSI-X irqs\n",
 			       pci_name(dev));
 			BUG_ON(warning > 0);
-		} else {
-			dev->irq = temp;
-			disable_msi_mode(dev,
-				pci_find_capability(dev, PCI_CAP_ID_MSIX),
-				PCI_CAP_ID_MSIX);
-
 		}
 	}
 }
 
 /**
- * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
+ * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
  * @dev: pointer to the pci_dev data structure of MSI(X) device function
  *
  * Being called during hotplug remove, from which the device function
- * is hot-removed. All previous assigned MSI/MSI-X vectors, if
+ * is hot-removed. All previous assigned MSI/MSI-X irqs, if
  * allocated for this device function, are reclaimed to unused state,
  * which may be used later on.
  **/
 void msi_remove_pci_irq_vectors(struct pci_dev* dev)
 {
-	int state, pos, temp;
+	int pos, temp;
 	unsigned long flags;
 
 	if (!pci_msi_enable || !dev)
@@ -1305,42 +902,38 @@
 
 	temp = dev->irq;		/* Save IOAPIC IRQ */
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-	if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
-		spin_lock_irqsave(&msi_lock, flags);
-		state = msi_desc[dev->irq]->msi_attrib.state;
-		spin_unlock_irqrestore(&msi_lock, flags);
-		if (state) {
+	if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+		if (irq_has_action(dev->irq)) {
 			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
-			       "called without free_irq() on MSI vector %d\n",
+			       "called without free_irq() on MSI irq %d\n",
 			       pci_name(dev), dev->irq);
-			BUG_ON(state > 0);
-		} else /* Release MSI vector assigned to this device */
-			msi_free_vector(dev, dev->irq, 0);
+			BUG_ON(irq_has_action(dev->irq));
+		} else /* Release MSI irq assigned to this device */
+			msi_free_irq(dev, dev->irq);
 		dev->irq = temp;		/* Restore IOAPIC IRQ */
 	}
 	pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-	if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
-		int vector, head, tail = 0, warning = 0;
+	if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+		int irq, head, tail = 0, warning = 0;
 		void __iomem *base = NULL;
 
-		vector = head = dev->irq;
+		irq = head = dev->irq;
 		while (head != tail) {
 			spin_lock_irqsave(&msi_lock, flags);
-			state = msi_desc[vector]->msi_attrib.state;
-			tail = msi_desc[vector]->link.tail;
-			base = msi_desc[vector]->mask_base;
+			tail = msi_desc[irq]->link.tail;
+			base = msi_desc[irq]->mask_base;
 			spin_unlock_irqrestore(&msi_lock, flags);
-			if (state)
+			if (irq_has_action(irq))
 				warning = 1;
-			else if (vector != head) /* Release MSI-X vector */
-				msi_free_vector(dev, vector, 0);
-			vector = tail;
+			else if (irq != head) /* Release MSI-X irq */
+				msi_free_irq(dev, irq);
+			irq = tail;
 		}
-		msi_free_vector(dev, vector, 0);
+		msi_free_irq(dev, irq);
 		if (warning) {
 			iounmap(base);
 			printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
-			       "called without free_irq() on all MSI-X vectors\n",
+			       "called without free_irq() on all MSI-X irqs\n",
 			       pci_name(dev));
 			BUG_ON(warning > 0);
 		}
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index 56951c3..f0cca17 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -7,84 +7,6 @@
 #define MSI_H
 
 /*
- * MSI operation vector.  Used by the msi core code (drivers/pci/msi.c)
- * to abstract platform-specific tasks relating to MSI address generation
- * and resource management.
- */
-struct msi_ops {
-	/**
-	 * setup - generate an MSI bus address and data for a given vector
-	 * @pdev: PCI device context (in)
-	 * @vector: vector allocated by the msi core (in)
-	 * @addr_hi: upper 32 bits of PCI bus MSI address (out)
-	 * @addr_lo: lower 32 bits of PCI bus MSI address (out)
-	 * @data: MSI data payload (out)
-	 *
-	 * Description: The setup op is used to generate a PCI bus addres and
-	 * data which the msi core will program into the card MSI capability
-	 * registers.  The setup routine is responsible for picking an initial
-	 * cpu to target the MSI at.  The setup routine is responsible for
-	 * examining pdev to determine the MSI capabilities of the card and
-	 * generating a suitable address/data.  The setup routine is
-	 * responsible for allocating and tracking any system resources it
-	 * needs to route the MSI to the cpu it picks, and for associating
-	 * those resources with the passed in vector.
-	 *
-	 * Returns 0 if the MSI address/data was successfully setup.
-	 **/
-
-	int	(*setup)    (struct pci_dev *pdev, unsigned int vector,
-			     u32 *addr_hi, u32 *addr_lo, u32 *data);
-
-	/**
-	 * teardown - release resources allocated by setup
-	 * @vector: vector context for resources (in)
-	 *
-	 * Description:  The teardown op is used to release any resources
-	 * that were allocated in the setup routine associated with the passed
-	 * in vector.
-	 **/
-
-	void	(*teardown) (unsigned int vector);
-
-	/**
-	 * target - retarget an MSI at a different cpu
-	 * @vector: vector context for resources (in)
-	 * @cpu:  new cpu to direct vector at (in)
-	 * @addr_hi: new value of PCI bus upper 32 bits (in/out)
-	 * @addr_lo: new value of PCI bus lower 32 bits (in/out)
-	 *
-	 * Description:  The target op is used to redirect an MSI vector
-	 * at a different cpu.  addr_hi/addr_lo coming in are the existing
-	 * values that the MSI core has programmed into the card.  The
-	 * target code is responsible for freeing any resources (if any)
-	 * associated with the old address, and generating a new PCI bus
-	 * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
-	 **/
-
-	void	(*target)   (unsigned int vector, unsigned int cpu,
-			     u32 *addr_hi, u32 *addr_lo);
-};
-
-extern int msi_register(struct msi_ops *ops);
-
-#include <asm/msi.h>
-
-/*
- * Assume the maximum number of hot plug slots supported by the system is about
- * ten. The worstcase is that each of these slots is hot-added with a device,
- * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
- * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
- * as below to ensure at least one message is assigned to each detected MSI/
- * MSI-X device function.
- */
-#define NR_HP_RESERVED_VECTORS 	20
-
-extern int vector_irq[NR_VECTORS];
-extern void (*interrupt[NR_IRQS])(void);
-extern int pci_vector_resources(int last, int nr_released);
-
-/*
  * MSI-X Address Register
  */
 #define PCI_MSIX_FLAGS_QSIZE		0x7FF
@@ -110,8 +32,8 @@
 	(1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
 #define multi_msi_enable(control, num) \
 	control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
-#define is_64bit_address(control)	(control & PCI_MSI_FLAGS_64BIT)
-#define is_mask_bit_support(control)	(control & PCI_MSI_FLAGS_MASKBIT)
+#define is_64bit_address(control)	(!!(control & PCI_MSI_FLAGS_64BIT))
+#define is_mask_bit_support(control)	(!!(control & PCI_MSI_FLAGS_MASKBIT))
 #define msi_enable(control, num) multi_msi_enable(control, num); \
 	control |= PCI_MSI_FLAGS_ENABLE
 
@@ -125,32 +47,4 @@
 #define msix_mask(address)		(address | PCI_MSIX_FLAGS_BITMASK)
 #define msix_is_pending(address) 	(address & PCI_MSIX_FLAGS_PENDMASK)
 
-struct msi_desc {
-	struct {
-		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
-		__u8	maskbit	: 1; 	/* mask-pending bit supported ?   */
-		__u8	state	: 1; 	/* {0: free, 1: busy}		  */
-		__u8	reserved: 1; 	/* reserved			  */
-		__u8	entry_nr;    	/* specific enabled entry 	  */
-		__u8	default_vector; /* default pre-assigned vector    */
-		__u8	unused; 	/* formerly unused destination cpu*/
-	}msi_attrib;
-
-	struct {
-		__u16	head;
-		__u16	tail;
-	}link;
-
-	void __iomem *mask_base;
-	struct pci_dev *dev;
-
-#ifdef CONFIG_PM
-	/* PM save area for MSIX address/data */
-
-	u32	address_hi_save;
-	u32	address_lo_save;
-	u32	data_save;
-#endif
-};
-
 #endif /* MSI_H */
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 5440491..8f7bcf5 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -55,16 +55,16 @@
 	list_for_each_entry(dev, &bus->devices, bus_list) {
 		u16 class = dev->class >> 8;
 
-		/* Don't touch classless devices or host bridges. */
+		/* Don't touch classless devices or host bridges or ioapics.  */
 		if (class == PCI_CLASS_NOT_DEFINED ||
 		    class == PCI_CLASS_BRIDGE_HOST)
 			continue;
 
-		/* Don't touch ioapics if it has the assigned resources. */
+		/* Don't touch ioapic devices already enabled by firmware */
 		if (class == PCI_CLASS_SYSTEM_PIC) {
-			res = &dev->resource[0];
-			if (res[0].start || res[1].start || res[2].start ||
-			    res[3].start || res[4].start || res[5].start)
+			u16 command;
+			pci_read_config_word(dev, PCI_COMMAND, &command);
+			if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
 				continue;
 		}
 
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index cc5032b..3f0f7b8 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -141,9 +141,9 @@
 
 	dev_dbg(dev, "%s secs=%d, mins=%d, "
 		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
-		"write", dt->tm_sec, dt->tm_min,
-		dt->tm_hour, dt->tm_mday,
-		dt->tm_mon, dt->tm_year, dt->tm_wday);
+		"write", t->tm_sec, t->tm_min,
+		t->tm_hour, t->tm_mday,
+		t->tm_mon, t->tm_year, t->tm_wday);
 
 	*buf++ = 0;		/* first register addr */
 	buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 9c68ec9..67e816a 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -55,7 +55,7 @@
 	}
 
 	dev_dbg(&client->dev,
-		"%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
+		"%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
 		__FUNCTION__, buf[0], buf[1], buf[2], buf[3]);
 
 	time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
@@ -96,7 +96,7 @@
 	unsigned long secs;
 
 	dev_dbg(&client->dev,
-		"%s: secs=%d, mins=%d, hours=%d, ",
+		"%s: secs=%d, mins=%d, hours=%d, "
 		"mday=%d, mon=%d, year=%d, wday=%d\n",
 		__FUNCTION__,
 		tm->tm_sec, tm->tm_min, tm->tm_hour,
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 2f0b777..0b20dfa 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -19,7 +19,6 @@
  *                - Initial driver creation.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index bbdad09..2a86632 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -91,7 +91,7 @@
 	unsigned char buf[8] = { RS5C372_REG_BASE };
 
 	dev_dbg(&client->dev,
-		"%s: secs=%d, mins=%d, hours=%d ",
+		"%s: secs=%d, mins=%d, hours=%d "
 		"mday=%d, mon=%d, year=%d, wday=%d\n",
 		__FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour,
 		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -126,7 +126,7 @@
 		return -EIO;
 	}
 
-	dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim);
+	dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim);
 
 	if (osc)
 		*osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768;
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index ee2ccad..734adc9 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -24,7 +24,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
index ece936a..8f6f32f 100644
--- a/drivers/scsi/imm.h
+++ b/drivers/scsi/imm.h
@@ -66,7 +66,6 @@
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
-#include  <linux/config.h>
 #include  <linux/stddef.h>
 #include  <linux/module.h>
 #include  <linux/kernel.h>
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index 7511df3..ba80214 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -73,7 +73,6 @@
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
-#include  <linux/config.h>
 #include  <linux/stddef.h>
 #include  <linux/module.h>
 #include  <linux/kernel.h>
diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
index 1ebe6b5..c5d0add 100644
--- a/drivers/serial/8250_gsc.c
+++ b/drivers/serial/8250_gsc.c
@@ -22,7 +22,6 @@
 #include <asm/hardware.h>
 #include <asm/parisc-device.h>
 #include <asm/io.h>
-#include <asm/serial.h> /* for LASI_BASE_BAUD */
 
 #include "8250.h"
 
@@ -54,7 +53,8 @@
 
 	memset(&port, 0, sizeof(port));
 	port.iotype	= UPIO_MEM;
-	port.uartclk	= LASI_BASE_BAUD * 16;
+	/* 7.272727MHz on Lasi.  Assumed the same for Dino, Wax and Timi. */
+	port.uartclk	= 7272727;
 	port.mapbase	= address;
 	port.membase	= ioremap_nocache(address, 16);
 	port.irq	= dev->irq;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 653098b..b0d5026 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -299,33 +299,33 @@
 	  your boot loader (lilo or loadlin) about how to pass options to the
 	  kernel at boot time.)
 
-config SERIAL_AT91
-	bool "AT91RM9200 / AT91SAM9261 serial port support"
-	depends on ARM && (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
+config SERIAL_ATMEL
+	bool "AT91 / AT32 on-chip serial port support"
+	depends on (ARM && ARCH_AT91) || AVR32
 	select SERIAL_CORE
 	help
 	  This enables the driver for the on-chip UARTs of the Atmel
-	  AT91RM9200 and AT91SAM926 processor.
+	  AT91 and AT32 processors.
 
-config SERIAL_AT91_CONSOLE
-	bool "Support for console on AT91RM9200 / AT91SAM9261 serial port"
-	depends on SERIAL_AT91=y
+config SERIAL_ATMEL_CONSOLE
+	bool "Support for console on AT91 / AT32 serial port"
+	depends on SERIAL_ATMEL=y
 	select SERIAL_CORE_CONSOLE
 	help
-	  Say Y here if you wish to use a UART on the Atmel AT91RM9200 or
-	  AT91SAM9261 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).
+	  Say Y here if you wish to use an on-chip UART on a Atmel
+	  AT91 or AT32 processor 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).
 
-config SERIAL_AT91_TTYAT
-	bool "Install as device ttyAT0-4 instead of ttyS0-4"
-	depends on SERIAL_AT91=y
+config SERIAL_ATMEL_TTYAT
+	bool "Install as device ttyATn instead of ttySn"
+	depends on SERIAL_ATMEL=y
 	help
-	  Say Y here if you wish to have the five internal AT91RM9200 UARTs
-	  appear as /dev/ttyAT0-4 (major 204, minor 154-158) instead of the
-	  normal /dev/ttyS0-4 (major 4, minor 64-68). This is necessary if
-	  you also want other UARTs, such as external 8250/16C550 compatible
-	  UARTs.
+	  Say Y here if you wish to have the internal AT91 / AT32 UARTs
+	  appear as /dev/ttyATn (major 204, minor starting at 154)
+	  instead of the normal /dev/ttySn (major 4, minor starting at
+	  64). This is necessary if you also want other UARTs, such as
+	  external 8250/16C550 compatible UARTs.
 	  The ttySn nodes are legally reserved for the 8250 serial driver
 	  but are often misused by other serial drivers.
 
@@ -556,10 +556,11 @@
 	default y
 	---help---
 	  Saying Y here will enable the hardware MUX serial driver for
-	  the Nova and K class systems.  The hardware MUX is not 8250/16550 
-	  compatible therefore the /dev/ttyB0 device is shared between the 
-	  Serial MUX and the PDC software console.  The following steps 
-	  need to be completed to use the Serial MUX:
+	  the Nova, K class systems and D class with a 'remote control card'.
+	  The hardware MUX is not 8250/16550 compatible therefore the
+	  /dev/ttyB0 device is shared between the Serial MUX and the PDC
+	  software console. The following steps need to be completed to use
+	  the Serial MUX:
 
 	    1. create the device entry (mknod /dev/ttyB0 c 11 0)
 	    2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 927faee..b4d8a7c 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -54,5 +54,5 @@
 obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
 obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
 obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
-obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
 obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c
deleted file mode 100644
index bf4bf10..0000000
--- a/drivers/serial/at91_serial.c
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- *  linux/drivers/char/at91_serial.c
- *
- *  Driver for Atmel AT91RM9200 Serial ports
- *  Copyright (C) 2003 Rick Bronson
- *
- *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
- *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- * 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/tty.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/tty_flip.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-
-#include <asm/arch/at91rm9200_usart.h>
-#include <asm/arch/at91rm9200_pdc.h>
-#include <asm/mach/serial_at91.h>
-#include <asm/arch/board.h>
-#include <asm/arch/system.h>
-#include <asm/arch/gpio.h>
-
-#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#ifdef CONFIG_SERIAL_AT91_TTYAT
-
-/* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
- * should coexist with the 8250 driver, such as if we have an external 16C550
- * UART. */
-#define SERIAL_AT91_MAJOR	204
-#define MINOR_START		154
-#define AT91_DEVICENAME		"ttyAT"
-
-#else
-
-/* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
- * name, but it is legally reserved for the 8250 driver. */
-#define SERIAL_AT91_MAJOR	TTY_MAJOR
-#define MINOR_START		64
-#define AT91_DEVICENAME		"ttyS"
-
-#endif
-
-#define AT91_ISR_PASS_LIMIT	256
-
-#define UART_PUT_CR(port,v)	writel(v, (port)->membase + AT91_US_CR)
-#define UART_GET_MR(port)	readl((port)->membase + AT91_US_MR)
-#define UART_PUT_MR(port,v)	writel(v, (port)->membase + AT91_US_MR)
-#define UART_PUT_IER(port,v)	writel(v, (port)->membase + AT91_US_IER)
-#define UART_PUT_IDR(port,v)	writel(v, (port)->membase + AT91_US_IDR)
-#define UART_GET_IMR(port)	readl((port)->membase + AT91_US_IMR)
-#define UART_GET_CSR(port)	readl((port)->membase + AT91_US_CSR)
-#define UART_GET_CHAR(port)	readl((port)->membase + AT91_US_RHR)
-#define UART_PUT_CHAR(port,v)	writel(v, (port)->membase + AT91_US_THR)
-#define UART_GET_BRGR(port)	readl((port)->membase + AT91_US_BRGR)
-#define UART_PUT_BRGR(port,v)	writel(v, (port)->membase + AT91_US_BRGR)
-#define UART_PUT_RTOR(port,v)	writel(v, (port)->membase + AT91_US_RTOR)
-
-// #define UART_GET_CR(port)	readl((port)->membase + AT91_US_CR)		// is write-only
-
- /* PDC registers */
-#define UART_PUT_PTCR(port,v)	writel(v, (port)->membase + AT91_PDC_PTCR)
-#define UART_GET_PTSR(port)	readl((port)->membase + AT91_PDC_PTSR)
-
-#define UART_PUT_RPR(port,v)	writel(v, (port)->membase + AT91_PDC_RPR)
-#define UART_GET_RPR(port)	readl((port)->membase + AT91_PDC_RPR)
-#define UART_PUT_RCR(port,v)	writel(v, (port)->membase + AT91_PDC_RCR)
-#define UART_PUT_RNPR(port,v)	writel(v, (port)->membase + AT91_PDC_RNPR)
-#define UART_PUT_RNCR(port,v)	writel(v, (port)->membase + AT91_PDC_RNCR)
-
-#define UART_PUT_TPR(port,v)	writel(v, (port)->membase + AT91_PDC_TPR)
-#define UART_PUT_TCR(port,v)	writel(v, (port)->membase + AT91_PDC_TCR)
-//#define UART_PUT_TNPR(port,v)	writel(v, (port)->membase + AT91_PDC_TNPR)
-//#define UART_PUT_TNCR(port,v)	writel(v, (port)->membase + AT91_PDC_TNCR)
-
-static int (*at91_open)(struct uart_port *);
-static void (*at91_close)(struct uart_port *);
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct at91_uart_port {
-	struct uart_port	uart;		/* uart */
-	struct clk		*clk;		/* uart clock */
-	unsigned short		suspended;	/* is port suspended? */
-};
-
-static struct at91_uart_port at91_ports[AT91_NR_UART];
-
-#ifdef SUPPORT_SYSRQ
-static struct console at91_console;
-#endif
-
-/*
- * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
- */
-static u_int at91_tx_empty(struct uart_port *port)
-{
-	return (UART_GET_CSR(port) & AT91_US_TXEMPTY) ? TIOCSER_TEMT : 0;
-}
-
-/*
- * Set state of the modem control output lines
- */
-static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
-{
-	unsigned int control = 0;
-	unsigned int mode;
-
-	if (arch_identify() == ARCH_ID_AT91RM9200) {
-		/*
-		 * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
-		 *  We need to drive the pin manually.
-		 */
-		if (port->mapbase == AT91RM9200_BASE_US0) {
-			if (mctrl & TIOCM_RTS)
-				at91_set_gpio_value(AT91_PIN_PA21, 0);
-			else
-				at91_set_gpio_value(AT91_PIN_PA21, 1);
-		}
-	}
-
-	if (mctrl & TIOCM_RTS)
-		control |= AT91_US_RTSEN;
-	else
-		control |= AT91_US_RTSDIS;
-
-	if (mctrl & TIOCM_DTR)
-		control |= AT91_US_DTREN;
-	else
-		control |= AT91_US_DTRDIS;
-
-	UART_PUT_CR(port, control);
-
-	/* Local loopback mode? */
-	mode = UART_GET_MR(port) & ~AT91_US_CHMODE;
-	if (mctrl & TIOCM_LOOP)
-		mode |= AT91_US_CHMODE_LOC_LOOP;
-	else
-		mode |= AT91_US_CHMODE_NORMAL;
-	UART_PUT_MR(port, mode);
-}
-
-/*
- * Get state of the modem control input lines
- */
-static u_int at91_get_mctrl(struct uart_port *port)
-{
-	unsigned int status, ret = 0;
-
-	status = UART_GET_CSR(port);
-
-	/*
-	 * The control signals are active low.
-	 */
-	if (!(status & AT91_US_DCD))
-		ret |= TIOCM_CD;
-	if (!(status & AT91_US_CTS))
-		ret |= TIOCM_CTS;
-	if (!(status & AT91_US_DSR))
-		ret |= TIOCM_DSR;
-	if (!(status & AT91_US_RI))
-		ret |= TIOCM_RI;
-
-	return ret;
-}
-
-/*
- * Stop transmitting.
- */
-static void at91_stop_tx(struct uart_port *port)
-{
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
-	UART_PUT_IDR(port, AT91_US_TXRDY);
-}
-
-/*
- * Start transmitting.
- */
-static void at91_start_tx(struct uart_port *port)
-{
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
-	UART_PUT_IER(port, AT91_US_TXRDY);
-}
-
-/*
- * Stop receiving - port is in process of being closed.
- */
-static void at91_stop_rx(struct uart_port *port)
-{
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
-	UART_PUT_IDR(port, AT91_US_RXRDY);
-}
-
-/*
- * Enable modem status interrupts
- */
-static void at91_enable_ms(struct uart_port *port)
-{
-	UART_PUT_IER(port, AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC);
-}
-
-/*
- * Control the transmission of a break signal
- */
-static void at91_break_ctl(struct uart_port *port, int break_state)
-{
-	if (break_state != 0)
-		UART_PUT_CR(port, AT91_US_STTBRK);	/* start break */
-	else
-		UART_PUT_CR(port, AT91_US_STPBRK);	/* stop break */
-}
-
-/*
- * Characters received (called from interrupt handler)
- */
-static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs)
-{
-	struct tty_struct *tty = port->info->tty;
-	unsigned int status, ch, flg;
-
-	status = UART_GET_CSR(port);
-	while (status & AT91_US_RXRDY) {
-		ch = UART_GET_CHAR(port);
-
-		port->icount.rx++;
-
-		flg = TTY_NORMAL;
-
-		/*
-		 * note that the error handling code is
-		 * out of the main execution path
-		 */
-		if (unlikely(status & (AT91_US_PARE | AT91_US_FRAME | AT91_US_OVRE | AT91_US_RXBRK))) {
-			UART_PUT_CR(port, AT91_US_RSTSTA);	/* clear error */
-			if (status & AT91_US_RXBRK) {
-				status &= ~(AT91_US_PARE | AT91_US_FRAME);	/* ignore side-effect */
-				port->icount.brk++;
-				if (uart_handle_break(port))
-					goto ignore_char;
-			}
-			if (status & AT91_US_PARE)
-				port->icount.parity++;
-			if (status & AT91_US_FRAME)
-				port->icount.frame++;
-			if (status & AT91_US_OVRE)
-				port->icount.overrun++;
-
-			status &= port->read_status_mask;
-
-			if (status & AT91_US_RXBRK)
-				flg = TTY_BREAK;
-			else if (status & AT91_US_PARE)
-				flg = TTY_PARITY;
-			else if (status & AT91_US_FRAME)
-				flg = TTY_FRAME;
-		}
-
-		if (uart_handle_sysrq_char(port, ch, regs))
-			goto ignore_char;
-
-		uart_insert_char(port, status, AT91_US_OVRE, ch, flg);
-
-	ignore_char:
-		status = UART_GET_CSR(port);
-	}
-
-	tty_flip_buffer_push(tty);
-}
-
-/*
- * Transmit characters (called from interrupt handler)
- */
-static void at91_tx_chars(struct uart_port *port)
-{
-	struct circ_buf *xmit = &port->info->xmit;
-
-	if (port->x_char) {
-		UART_PUT_CHAR(port, port->x_char);
-		port->icount.tx++;
-		port->x_char = 0;
-		return;
-	}
-	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-		at91_stop_tx(port);
-		return;
-	}
-
-	while (UART_GET_CSR(port) & AT91_US_TXRDY) {
-		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
-		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-		port->icount.tx++;
-		if (uart_circ_empty(xmit))
-			break;
-	}
-
-	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-		uart_write_wakeup(port);
-
-	if (uart_circ_empty(xmit))
-		at91_stop_tx(port);
-}
-
-/*
- * Interrupt handler
- */
-static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct uart_port *port = dev_id;
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-	unsigned int status, pending, pass_counter = 0;
-
-	status = UART_GET_CSR(port);
-	pending = status & UART_GET_IMR(port);
-	while (pending) {
-		/* Interrupt receive */
-		if (pending & AT91_US_RXRDY)
-			at91_rx_chars(port, regs);
-
-		// TODO: All reads to CSR will clear these interrupts!
-		if (pending & AT91_US_RIIC) port->icount.rng++;
-		if (pending & AT91_US_DSRIC) port->icount.dsr++;
-		if (pending & AT91_US_DCDIC)
-			uart_handle_dcd_change(port, !(status & AT91_US_DCD));
-		if (pending & AT91_US_CTSIC)
-			uart_handle_cts_change(port, !(status & AT91_US_CTS));
-		if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC))
-			wake_up_interruptible(&port->info->delta_msr_wait);
-
-		/* Interrupt transmit */
-		if (pending & AT91_US_TXRDY)
-			at91_tx_chars(port);
-
-		if (pass_counter++ > AT91_ISR_PASS_LIMIT)
-			break;
-
-		status = UART_GET_CSR(port);
-		pending = status & UART_GET_IMR(port);
-	}
-	return IRQ_HANDLED;
-}
-
-/*
- * Perform initialization and enable port for reception
- */
-static int at91_startup(struct uart_port *port)
-{
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-	int retval;
-
-	/*
-	 * Ensure that no interrupts are enabled otherwise when
-	 * request_irq() is called we could get stuck trying to
-	 * handle an unexpected interrupt
-	 */
-	UART_PUT_IDR(port, -1);
-
-	/*
-	 * Allocate the IRQ
-	 */
-	retval = request_irq(port->irq, at91_interrupt, IRQF_SHARED, "at91_serial", port);
-	if (retval) {
-		printk("at91_serial: at91_startup - Can't get irq\n");
-		return retval;
-	}
-
-	/*
-	 * If there is a specific "open" function (to register
-	 * control line interrupts)
-	 */
-	if (at91_open) {
-		retval = at91_open(port);
-		if (retval) {
-			free_irq(port->irq, port);
-			return retval;
-		}
-	}
-
-	/*
-	 * Finally, enable the serial port
-	 */
-	UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
-	UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN);		/* enable xmit & rcvr */
-
-	UART_PUT_IER(port, AT91_US_RXRDY);		/* enable receive only */
-
-	return 0;
-}
-
-/*
- * Disable the port
- */
-static void at91_shutdown(struct uart_port *port)
-{
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
-	/*
-	 * Disable all interrupts, port and break condition.
-	 */
-	UART_PUT_CR(port, AT91_US_RSTSTA);
-	UART_PUT_IDR(port, -1);
-
-	/*
-	 * Free the interrupt
-	 */
-	free_irq(port->irq, port);
-
-	/*
-	 * If there is a specific "close" function (to unregister
-	 * control line interrupts)
-	 */
-	if (at91_close)
-		at91_close(port);
-}
-
-/*
- * Power / Clock management.
- */
-static void at91_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
-{
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
-	switch (state) {
-		case 0:
-			/*
-			 * Enable the peripheral clock for this serial port.
-			 * This is called on uart_open() or a resume event.
-			 */
-			clk_enable(at91_port->clk);
-			break;
-		case 3:
-			/*
-			 * Disable the peripheral clock for this serial port.
-			 * This is called on uart_close() or a suspend event.
-			 */
-			clk_disable(at91_port->clk);
-			break;
-		default:
-			printk(KERN_ERR "at91_serial: unknown pm %d\n", state);
-	}
-}
-
-/*
- * Change the port parameters
- */
-static void at91_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
-{
-	unsigned long flags;
-	unsigned int mode, imr, quot, baud;
-
-	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
-	quot = uart_get_divisor(port, baud);
-
-	/* Get current mode register */
-	mode = UART_GET_MR(port) & ~(AT91_US_CHRL | AT91_US_NBSTOP | AT91_US_PAR);
-
-	/* byte size */
-	switch (termios->c_cflag & CSIZE) {
-	case CS5:
-		mode |= AT91_US_CHRL_5;
-		break;
-	case CS6:
-		mode |= AT91_US_CHRL_6;
-		break;
-	case CS7:
-		mode |= AT91_US_CHRL_7;
-		break;
-	default:
-		mode |= AT91_US_CHRL_8;
-		break;
-	}
-
-	/* stop bits */
-	if (termios->c_cflag & CSTOPB)
-		mode |= AT91_US_NBSTOP_2;
-
-	/* parity */
-	if (termios->c_cflag & PARENB) {
-		if (termios->c_cflag & CMSPAR) {			/* Mark or Space parity */
-			if (termios->c_cflag & PARODD)
-				mode |= AT91_US_PAR_MARK;
-			else
-				mode |= AT91_US_PAR_SPACE;
-		}
-		else if (termios->c_cflag & PARODD)
-			mode |= AT91_US_PAR_ODD;
-		else
-			mode |= AT91_US_PAR_EVEN;
-	}
-	else
-		mode |= AT91_US_PAR_NONE;
-
-	spin_lock_irqsave(&port->lock, flags);
-
-	port->read_status_mask = AT91_US_OVRE;
-	if (termios->c_iflag & INPCK)
-		port->read_status_mask |= (AT91_US_FRAME | AT91_US_PARE);
-	if (termios->c_iflag & (BRKINT | PARMRK))
-		port->read_status_mask |= AT91_US_RXBRK;
-
-	/*
-	 * Characters to ignore
-	 */
-	port->ignore_status_mask = 0;
-	if (termios->c_iflag & IGNPAR)
-		port->ignore_status_mask |= (AT91_US_FRAME | AT91_US_PARE);
-	if (termios->c_iflag & IGNBRK) {
-		port->ignore_status_mask |= AT91_US_RXBRK;
-		/*
-		 * If we're ignoring parity and break indicators,
-		 * ignore overruns too (for real raw support).
-		 */
-		if (termios->c_iflag & IGNPAR)
-			port->ignore_status_mask |= AT91_US_OVRE;
-	}
-
-	// TODO: Ignore all characters if CREAD is set.
-
-	/* update the per-port timeout */
-	uart_update_timeout(port, termios->c_cflag, baud);
-
-	/* disable interrupts and drain transmitter */
-	imr = UART_GET_IMR(port);	/* get interrupt mask */
-	UART_PUT_IDR(port, -1);		/* disable all interrupts */
-	while (!(UART_GET_CSR(port) & AT91_US_TXEMPTY)) { barrier(); }
-
-	/* disable receiver and transmitter */
-	UART_PUT_CR(port, AT91_US_TXDIS | AT91_US_RXDIS);
-
-	/* set the parity, stop bits and data size */
-	UART_PUT_MR(port, mode);
-
-	/* set the baud rate */
-	UART_PUT_BRGR(port, quot);
-	UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
-	UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN);
-
-	/* restore interrupts */
-	UART_PUT_IER(port, imr);
-
-	/* CTS flow-control and modem-status interrupts */
-	if (UART_ENABLE_MS(port, termios->c_cflag))
-		port->ops->enable_ms(port);
-
-	spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * Return string describing the specified port
- */
-static const char *at91_type(struct uart_port *port)
-{
-	return (port->type == PORT_AT91) ? "AT91_SERIAL" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void at91_release_port(struct uart_port *port)
-{
-	struct platform_device *pdev = to_platform_device(port->dev);
-	int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
-	release_mem_region(port->mapbase, size);
-
-	if (port->flags & UPF_IOREMAP) {
-		iounmap(port->membase);
-		port->membase = NULL;
-	}
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int at91_request_port(struct uart_port *port)
-{
-	struct platform_device *pdev = to_platform_device(port->dev);
-	int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
-	if (!request_mem_region(port->mapbase, size, "at91_serial"))
-		return -EBUSY;
-
-	if (port->flags & UPF_IOREMAP) {
-		port->membase = ioremap(port->mapbase, size);
-		if (port->membase == NULL) {
-			release_mem_region(port->mapbase, size);
-			return -ENOMEM;
-		}
-	}
-
-	return 0;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void at91_config_port(struct uart_port *port, int flags)
-{
-	if (flags & UART_CONFIG_TYPE) {
-		port->type = PORT_AT91;
-		at91_request_port(port);
-	}
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- */
-static int at91_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
-	int ret = 0;
-	if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91)
-		ret = -EINVAL;
-	if (port->irq != ser->irq)
-		ret = -EINVAL;
-	if (ser->io_type != SERIAL_IO_MEM)
-		ret = -EINVAL;
-	if (port->uartclk / 16 != ser->baud_base)
-		ret = -EINVAL;
-	if ((void *)port->mapbase != ser->iomem_base)
-		ret = -EINVAL;
-	if (port->iobase != ser->port)
-		ret = -EINVAL;
-	if (ser->hub6 != 0)
-		ret = -EINVAL;
-	return ret;
-}
-
-static struct uart_ops at91_pops = {
-	.tx_empty	= at91_tx_empty,
-	.set_mctrl	= at91_set_mctrl,
-	.get_mctrl	= at91_get_mctrl,
-	.stop_tx	= at91_stop_tx,
-	.start_tx	= at91_start_tx,
-	.stop_rx	= at91_stop_rx,
-	.enable_ms	= at91_enable_ms,
-	.break_ctl	= at91_break_ctl,
-	.startup	= at91_startup,
-	.shutdown	= at91_shutdown,
-	.set_termios	= at91_set_termios,
-	.type		= at91_type,
-	.release_port	= at91_release_port,
-	.request_port	= at91_request_port,
-	.config_port	= at91_config_port,
-	.verify_port	= at91_verify_port,
-	.pm		= at91_serial_pm,
-};
-
-/*
- * Configure the port from the platform device resource info.
- */
-static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct platform_device *pdev)
-{
-	struct uart_port *port = &at91_port->uart;
-	struct at91_uart_data *data = pdev->dev.platform_data;
-
-	port->iotype	= UPIO_MEM;
-	port->flags     = UPF_BOOT_AUTOCONF;
-	port->ops	= &at91_pops;
-	port->fifosize  = 1;
-	port->line	= pdev->id;
-	port->dev	= &pdev->dev;
-
-	port->mapbase	= pdev->resource[0].start;
-	port->irq	= pdev->resource[1].start;
-
-	if (port->mapbase == AT91_VA_BASE_SYS + AT91_DBGU)		/* Part of system perpherals - already mapped */
-		port->membase = (void __iomem *) port->mapbase;
-	else {
-		port->flags	|= UPF_IOREMAP;
-		port->membase	= NULL;
-	}
-
-	if (!at91_port->clk) {		/* for console, the clock could already be configured */
-		at91_port->clk = clk_get(&pdev->dev, "usart");
-		clk_enable(at91_port->clk);
-		port->uartclk = clk_get_rate(at91_port->clk);
-	}
-}
-
-/*
- * Register board-specific modem-control line handlers.
- */
-void __init at91_register_uart_fns(struct at91_port_fns *fns)
-{
-	if (fns->enable_ms)
-		at91_pops.enable_ms = fns->enable_ms;
-	if (fns->get_mctrl)
-		at91_pops.get_mctrl = fns->get_mctrl;
-	if (fns->set_mctrl)
-		at91_pops.set_mctrl = fns->set_mctrl;
-	at91_open          = fns->open;
-	at91_close         = fns->close;
-	at91_pops.pm       = fns->pm;
-	at91_pops.set_wake = fns->set_wake;
-}
-
-
-#ifdef CONFIG_SERIAL_AT91_CONSOLE
-static void at91_console_putchar(struct uart_port *port, int ch)
-{
-	while (!(UART_GET_CSR(port) & AT91_US_TXRDY))
-		barrier();
-	UART_PUT_CHAR(port, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void at91_console_write(struct console *co, const char *s, u_int count)
-{
-	struct uart_port *port = &at91_ports[co->index].uart;
-	unsigned int status, imr;
-
-	/*
-	 *	First, save IMR and then disable interrupts
-	 */
-	imr = UART_GET_IMR(port);	/* get interrupt mask */
-	UART_PUT_IDR(port, AT91_US_RXRDY | AT91_US_TXRDY);
-
-	uart_console_write(port, s, count, at91_console_putchar);
-
-	/*
-	 *	Finally, wait for transmitter to become empty
-	 *	and restore IMR
-	 */
-	do {
-		status = UART_GET_CSR(port);
-	} while (!(status & AT91_US_TXRDY));
-	UART_PUT_IER(port, imr);	/* set interrupts back the way they were */
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader), try to determine
- * the current setup.
- */
-static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
-{
-	unsigned int mr, quot;
-
-// TODO: CR is a write-only register
-//	unsigned int cr;
-//
-//	cr = UART_GET_CR(port) & (AT91_US_RXEN | AT91_US_TXEN);
-//	if (cr == (AT91_US_RXEN | AT91_US_TXEN)) {
-//		/* ok, the port was enabled */
-//	}
-
-	mr = UART_GET_MR(port) & AT91_US_CHRL;
-	if (mr == AT91_US_CHRL_8)
-		*bits = 8;
-	else
-		*bits = 7;
-
-	mr = UART_GET_MR(port) & AT91_US_PAR;
-	if (mr == AT91_US_PAR_EVEN)
-		*parity = 'e';
-	else if (mr == AT91_US_PAR_ODD)
-		*parity = 'o';
-
-	quot = UART_GET_BRGR(port);
-	*baud = port->uartclk / (16 * (quot));
-}
-
-static int __init at91_console_setup(struct console *co, char *options)
-{
-	struct uart_port *port = &at91_ports[co->index].uart;
-	int baud = 115200;
-	int bits = 8;
-	int parity = 'n';
-	int flow = 'n';
-
-	if (port->membase == 0)		/* Port not initialized yet - delay setup */
-		return -ENODEV;
-
-	UART_PUT_IDR(port, -1);				/* disable interrupts */
-	UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
-	UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN);
-
-	if (options)
-		uart_parse_options(options, &baud, &parity, &bits, &flow);
-	else
-		at91_console_get_options(port, &baud, &parity, &bits);
-
-	return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver at91_uart;
-
-static struct console at91_console = {
-	.name		= AT91_DEVICENAME,
-	.write		= at91_console_write,
-	.device		= uart_console_device,
-	.setup		= at91_console_setup,
-	.flags		= CON_PRINTBUFFER,
-	.index		= -1,
-	.data		= &at91_uart,
-};
-
-#define AT91_CONSOLE_DEVICE	&at91_console
-
-/*
- * Early console initialization (before VM subsystem initialized).
- */
-static int __init at91_console_init(void)
-{
-	if (at91_default_console_device) {
-		add_preferred_console(AT91_DEVICENAME, at91_default_console_device->id, NULL);
-		at91_init_port(&(at91_ports[at91_default_console_device->id]), at91_default_console_device);
-		register_console(&at91_console);
-	}
-
-	return 0;
-}
-console_initcall(at91_console_init);
-
-/*
- * Late console initialization.
- */
-static int __init at91_late_console_init(void)
-{
-	if (at91_default_console_device && !(at91_console.flags & CON_ENABLED))
-		register_console(&at91_console);
-
-	return 0;
-}
-core_initcall(at91_late_console_init);
-
-#else
-#define AT91_CONSOLE_DEVICE	NULL
-#endif
-
-static struct uart_driver at91_uart = {
-	.owner			= THIS_MODULE,
-	.driver_name		= "at91_serial",
-	.dev_name		= AT91_DEVICENAME,
-	.major			= SERIAL_AT91_MAJOR,
-	.minor			= MINOR_START,
-	.nr			= AT91_NR_UART,
-	.cons			= AT91_CONSOLE_DEVICE,
-};
-
-#ifdef CONFIG_PM
-static int at91_serial_suspend(struct platform_device *pdev, pm_message_t state)
-{
-	struct uart_port *port = platform_get_drvdata(pdev);
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
-	if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
-		enable_irq_wake(port->irq);
-	else {
-		disable_irq_wake(port->irq);
-		uart_suspend_port(&at91_uart, port);
-		at91_port->suspended = 1;
-	}
-
-	return 0;
-}
-
-static int at91_serial_resume(struct platform_device *pdev)
-{
-	struct uart_port *port = platform_get_drvdata(pdev);
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
-	if (at91_port->suspended) {
-		uart_resume_port(&at91_uart, port);
-		at91_port->suspended = 0;
-	}
-
-	return 0;
-}
-#else
-#define at91_serial_suspend NULL
-#define at91_serial_resume NULL
-#endif
-
-static int __devinit at91_serial_probe(struct platform_device *pdev)
-{
-	struct at91_uart_port *port;
-	int ret;
-
-	port = &at91_ports[pdev->id];
-	at91_init_port(port, pdev);
-
-	ret = uart_add_one_port(&at91_uart, &port->uart);
-	if (!ret) {
-		device_init_wakeup(&pdev->dev, 1);
-		platform_set_drvdata(pdev, port);
-	}
-
-	return ret;
-}
-
-static int __devexit at91_serial_remove(struct platform_device *pdev)
-{
-	struct uart_port *port = platform_get_drvdata(pdev);
-	struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-	int ret = 0;
-
-	clk_disable(at91_port->clk);
-	clk_put(at91_port->clk);
-
-	device_init_wakeup(&pdev->dev, 0);
-	platform_set_drvdata(pdev, NULL);
-
-	if (port) {
-		ret = uart_remove_one_port(&at91_uart, port);
-		kfree(port);
-	}
-
-	return ret;
-}
-
-static struct platform_driver at91_serial_driver = {
-	.probe		= at91_serial_probe,
-	.remove		= __devexit_p(at91_serial_remove),
-	.suspend	= at91_serial_suspend,
-	.resume		= at91_serial_resume,
-	.driver		= {
-		.name	= "at91_usart",
-		.owner	= THIS_MODULE,
-	},
-};
-
-static int __init at91_serial_init(void)
-{
-	int ret;
-
-	ret = uart_register_driver(&at91_uart);
-	if (ret)
-		return ret;
-
-	ret = platform_driver_register(&at91_serial_driver);
-	if (ret)
-		uart_unregister_driver(&at91_uart);
-
-	return ret;
-}
-
-static void __exit at91_serial_exit(void)
-{
-	platform_driver_unregister(&at91_serial_driver);
-	uart_unregister_driver(&at91_uart);
-}
-
-module_init(at91_serial_init);
-module_exit(at91_serial_exit);
-
-MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("AT91 generic serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
new file mode 100644
index 0000000..955c46d
--- /dev/null
+++ b/drivers/serial/atmel_serial.c
@@ -0,0 +1,992 @@
+/*
+ *  linux/drivers/char/at91_serial.c
+ *
+ *  Driver for Atmel AT91 / AT32 Serial ports
+ *  Copyright (C) 2003 Rick Bronson
+ *
+ *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
+ *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * 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/tty.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/at91rm9200_pdc.h>
+#include <asm/mach/serial_at91.h>
+#include <asm/arch/board.h>
+#ifdef CONFIG_ARM
+#include <asm/arch/system.h>
+#include <asm/arch/gpio.h>
+#endif
+
+#include "atmel_serial.h"
+
+#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#ifdef CONFIG_SERIAL_ATMEL_TTYAT
+
+/* Use device name ttyAT, major 204 and minor 154-169.  This is necessary if we
+ * should coexist with the 8250 driver, such as if we have an external 16C550
+ * UART. */
+#define SERIAL_ATMEL_MAJOR	204
+#define MINOR_START		154
+#define ATMEL_DEVICENAME	"ttyAT"
+
+#else
+
+/* Use device name ttyS, major 4, minor 64-68.  This is the usual serial port
+ * name, but it is legally reserved for the 8250 driver. */
+#define SERIAL_ATMEL_MAJOR	TTY_MAJOR
+#define MINOR_START		64
+#define ATMEL_DEVICENAME	"ttyS"
+
+#endif
+
+#define ATMEL_ISR_PASS_LIMIT	256
+
+#define UART_PUT_CR(port,v)	writel(v, (port)->membase + ATMEL_US_CR)
+#define UART_GET_MR(port)	readl((port)->membase + ATMEL_US_MR)
+#define UART_PUT_MR(port,v)	writel(v, (port)->membase + ATMEL_US_MR)
+#define UART_PUT_IER(port,v)	writel(v, (port)->membase + ATMEL_US_IER)
+#define UART_PUT_IDR(port,v)	writel(v, (port)->membase + ATMEL_US_IDR)
+#define UART_GET_IMR(port)	readl((port)->membase + ATMEL_US_IMR)
+#define UART_GET_CSR(port)	readl((port)->membase + ATMEL_US_CSR)
+#define UART_GET_CHAR(port)	readl((port)->membase + ATMEL_US_RHR)
+#define UART_PUT_CHAR(port,v)	writel(v, (port)->membase + ATMEL_US_THR)
+#define UART_GET_BRGR(port)	readl((port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_BRGR(port,v)	writel(v, (port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_RTOR(port,v)	writel(v, (port)->membase + ATMEL_US_RTOR)
+
+// #define UART_GET_CR(port)	readl((port)->membase + ATMEL_US_CR)		// is write-only
+
+ /* PDC registers */
+#define UART_PUT_PTCR(port,v)	writel(v, (port)->membase + ATMEL_PDC_PTCR)
+#define UART_GET_PTSR(port)	readl((port)->membase + ATMEL_PDC_PTSR)
+
+#define UART_PUT_RPR(port,v)	writel(v, (port)->membase + ATMEL_PDC_RPR)
+#define UART_GET_RPR(port)	readl((port)->membase + ATMEL_PDC_RPR)
+#define UART_PUT_RCR(port,v)	writel(v, (port)->membase + ATMEL_PDC_RCR)
+#define UART_PUT_RNPR(port,v)	writel(v, (port)->membase + ATMEL_PDC_RNPR)
+#define UART_PUT_RNCR(port,v)	writel(v, (port)->membase + ATMEL_PDC_RNCR)
+
+#define UART_PUT_TPR(port,v)	writel(v, (port)->membase + ATMEL_PDC_TPR)
+#define UART_PUT_TCR(port,v)	writel(v, (port)->membase + ATMEL_PDC_TCR)
+//#define UART_PUT_TNPR(port,v)	writel(v, (port)->membase + ATMEL_PDC_TNPR)
+//#define UART_PUT_TNCR(port,v)	writel(v, (port)->membase + ATMEL_PDC_TNCR)
+
+static int (*atmel_open_hook)(struct uart_port *);
+static void (*atmel_close_hook)(struct uart_port *);
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct atmel_uart_port {
+	struct uart_port	uart;		/* uart */
+	struct clk		*clk;		/* uart clock */
+	unsigned short		suspended;	/* is port suspended? */
+};
+
+static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+
+#ifdef SUPPORT_SYSRQ
+static struct console atmel_console;
+#endif
+
+/*
+ * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
+ */
+static u_int atmel_tx_empty(struct uart_port *port)
+{
+	return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
+}
+
+/*
+ * Set state of the modem control output lines
+ */
+static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+	unsigned int control = 0;
+	unsigned int mode;
+
+#ifdef CONFIG_ARM
+	if (arch_identify() == ARCH_ID_AT91RM9200) {
+		/*
+		 * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
+		 *  We need to drive the pin manually.
+		 */
+		if (port->mapbase == AT91RM9200_BASE_US0) {
+			if (mctrl & TIOCM_RTS)
+				at91_set_gpio_value(AT91_PIN_PA21, 0);
+			else
+				at91_set_gpio_value(AT91_PIN_PA21, 1);
+		}
+	}
+#endif
+
+	if (mctrl & TIOCM_RTS)
+		control |= ATMEL_US_RTSEN;
+	else
+		control |= ATMEL_US_RTSDIS;
+
+	if (mctrl & TIOCM_DTR)
+		control |= ATMEL_US_DTREN;
+	else
+		control |= ATMEL_US_DTRDIS;
+
+	UART_PUT_CR(port, control);
+
+	/* Local loopback mode? */
+	mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+	if (mctrl & TIOCM_LOOP)
+		mode |= ATMEL_US_CHMODE_LOC_LOOP;
+	else
+		mode |= ATMEL_US_CHMODE_NORMAL;
+	UART_PUT_MR(port, mode);
+}
+
+/*
+ * Get state of the modem control input lines
+ */
+static u_int atmel_get_mctrl(struct uart_port *port)
+{
+	unsigned int status, ret = 0;
+
+	status = UART_GET_CSR(port);
+
+	/*
+	 * The control signals are active low.
+	 */
+	if (!(status & ATMEL_US_DCD))
+		ret |= TIOCM_CD;
+	if (!(status & ATMEL_US_CTS))
+		ret |= TIOCM_CTS;
+	if (!(status & ATMEL_US_DSR))
+		ret |= TIOCM_DSR;
+	if (!(status & ATMEL_US_RI))
+		ret |= TIOCM_RI;
+
+	return ret;
+}
+
+/*
+ * Stop transmitting.
+ */
+static void atmel_stop_tx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+	UART_PUT_IDR(port, ATMEL_US_TXRDY);
+}
+
+/*
+ * Start transmitting.
+ */
+static void atmel_start_tx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+	UART_PUT_IER(port, ATMEL_US_TXRDY);
+}
+
+/*
+ * Stop receiving - port is in process of being closed.
+ */
+static void atmel_stop_rx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+	UART_PUT_IDR(port, ATMEL_US_RXRDY);
+}
+
+/*
+ * Enable modem status interrupts
+ */
+static void atmel_enable_ms(struct uart_port *port)
+{
+	UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+}
+
+/*
+ * Control the transmission of a break signal
+ */
+static void atmel_break_ctl(struct uart_port *port, int break_state)
+{
+	if (break_state != 0)
+		UART_PUT_CR(port, ATMEL_US_STTBRK);	/* start break */
+	else
+		UART_PUT_CR(port, ATMEL_US_STPBRK);	/* stop break */
+}
+
+/*
+ * Characters received (called from interrupt handler)
+ */
+static void atmel_rx_chars(struct uart_port *port, struct pt_regs *regs)
+{
+	struct tty_struct *tty = port->info->tty;
+	unsigned int status, ch, flg;
+
+	status = UART_GET_CSR(port);
+	while (status & ATMEL_US_RXRDY) {
+		ch = UART_GET_CHAR(port);
+
+		port->icount.rx++;
+
+		flg = TTY_NORMAL;
+
+		/*
+		 * note that the error handling code is
+		 * out of the main execution path
+		 */
+		if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+			UART_PUT_CR(port, ATMEL_US_RSTSTA);	/* clear error */
+			if (status & ATMEL_US_RXBRK) {
+				status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);	/* ignore side-effect */
+				port->icount.brk++;
+				if (uart_handle_break(port))
+					goto ignore_char;
+			}
+			if (status & ATMEL_US_PARE)
+				port->icount.parity++;
+			if (status & ATMEL_US_FRAME)
+				port->icount.frame++;
+			if (status & ATMEL_US_OVRE)
+				port->icount.overrun++;
+
+			status &= port->read_status_mask;
+
+			if (status & ATMEL_US_RXBRK)
+				flg = TTY_BREAK;
+			else if (status & ATMEL_US_PARE)
+				flg = TTY_PARITY;
+			else if (status & ATMEL_US_FRAME)
+				flg = TTY_FRAME;
+		}
+
+		if (uart_handle_sysrq_char(port, ch, regs))
+			goto ignore_char;
+
+		uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg);
+
+	ignore_char:
+		status = UART_GET_CSR(port);
+	}
+
+	tty_flip_buffer_push(tty);
+}
+
+/*
+ * Transmit characters (called from interrupt handler)
+ */
+static void atmel_tx_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+
+	if (port->x_char) {
+		UART_PUT_CHAR(port, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		atmel_stop_tx(port);
+		return;
+	}
+
+	while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
+		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		port->icount.tx++;
+		if (uart_circ_empty(xmit))
+			break;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		atmel_stop_tx(port);
+}
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t atmel_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct uart_port *port = dev_id;
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+	unsigned int status, pending, pass_counter = 0;
+
+	status = UART_GET_CSR(port);
+	pending = status & UART_GET_IMR(port);
+	while (pending) {
+		/* Interrupt receive */
+		if (pending & ATMEL_US_RXRDY)
+			atmel_rx_chars(port, regs);
+
+		// TODO: All reads to CSR will clear these interrupts!
+		if (pending & ATMEL_US_RIIC) port->icount.rng++;
+		if (pending & ATMEL_US_DSRIC) port->icount.dsr++;
+		if (pending & ATMEL_US_DCDIC)
+			uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
+		if (pending & ATMEL_US_CTSIC)
+			uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
+		if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC))
+			wake_up_interruptible(&port->info->delta_msr_wait);
+
+		/* Interrupt transmit */
+		if (pending & ATMEL_US_TXRDY)
+			atmel_tx_chars(port);
+
+		if (pass_counter++ > ATMEL_ISR_PASS_LIMIT)
+			break;
+
+		status = UART_GET_CSR(port);
+		pending = status & UART_GET_IMR(port);
+	}
+	return IRQ_HANDLED;
+}
+
+/*
+ * Perform initialization and enable port for reception
+ */
+static int atmel_startup(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+	int retval;
+
+	/*
+	 * Ensure that no interrupts are enabled otherwise when
+	 * request_irq() is called we could get stuck trying to
+	 * handle an unexpected interrupt
+	 */
+	UART_PUT_IDR(port, -1);
+
+	/*
+	 * Allocate the IRQ
+	 */
+	retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port);
+	if (retval) {
+		printk("atmel_serial: atmel_startup - Can't get irq\n");
+		return retval;
+	}
+
+	/*
+	 * If there is a specific "open" function (to register
+	 * control line interrupts)
+	 */
+	if (atmel_open_hook) {
+		retval = atmel_open_hook(port);
+		if (retval) {
+			free_irq(port->irq, port);
+			return retval;
+		}
+	}
+
+	/*
+	 * Finally, enable the serial port
+	 */
+	UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);		/* enable xmit & rcvr */
+
+	UART_PUT_IER(port, ATMEL_US_RXRDY);		/* enable receive only */
+
+	return 0;
+}
+
+/*
+ * Disable the port
+ */
+static void atmel_shutdown(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+	/*
+	 * Disable all interrupts, port and break condition.
+	 */
+	UART_PUT_CR(port, ATMEL_US_RSTSTA);
+	UART_PUT_IDR(port, -1);
+
+	/*
+	 * Free the interrupt
+	 */
+	free_irq(port->irq, port);
+
+	/*
+	 * If there is a specific "close" function (to unregister
+	 * control line interrupts)
+	 */
+	if (atmel_close_hook)
+		atmel_close_hook(port);
+}
+
+/*
+ * Power / Clock management.
+ */
+static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+	switch (state) {
+		case 0:
+			/*
+			 * Enable the peripheral clock for this serial port.
+			 * This is called on uart_open() or a resume event.
+			 */
+			clk_enable(atmel_port->clk);
+			break;
+		case 3:
+			/*
+			 * Disable the peripheral clock for this serial port.
+			 * This is called on uart_close() or a suspend event.
+			 */
+			clk_disable(atmel_port->clk);
+			break;
+		default:
+			printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
+	}
+}
+
+/*
+ * Change the port parameters
+ */
+static void atmel_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
+{
+	unsigned long flags;
+	unsigned int mode, imr, quot, baud;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+	quot = uart_get_divisor(port, baud);
+
+	/* Get current mode register */
+	mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
+	/* byte size */
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		mode |= ATMEL_US_CHRL_5;
+		break;
+	case CS6:
+		mode |= ATMEL_US_CHRL_6;
+		break;
+	case CS7:
+		mode |= ATMEL_US_CHRL_7;
+		break;
+	default:
+		mode |= ATMEL_US_CHRL_8;
+		break;
+	}
+
+	/* stop bits */
+	if (termios->c_cflag & CSTOPB)
+		mode |= ATMEL_US_NBSTOP_2;
+
+	/* parity */
+	if (termios->c_cflag & PARENB) {
+		if (termios->c_cflag & CMSPAR) {			/* Mark or Space parity */
+			if (termios->c_cflag & PARODD)
+				mode |= ATMEL_US_PAR_MARK;
+			else
+				mode |= ATMEL_US_PAR_SPACE;
+		}
+		else if (termios->c_cflag & PARODD)
+			mode |= ATMEL_US_PAR_ODD;
+		else
+			mode |= ATMEL_US_PAR_EVEN;
+	}
+	else
+		mode |= ATMEL_US_PAR_NONE;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	port->read_status_mask = ATMEL_US_OVRE;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		port->read_status_mask |= ATMEL_US_RXBRK;
+
+	/*
+	 * Characters to ignore
+	 */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= ATMEL_US_RXBRK;
+		/*
+		 * If we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= ATMEL_US_OVRE;
+	}
+
+	// TODO: Ignore all characters if CREAD is set.
+
+	/* update the per-port timeout */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	/* disable interrupts and drain transmitter */
+	imr = UART_GET_IMR(port);	/* get interrupt mask */
+	UART_PUT_IDR(port, -1);		/* disable all interrupts */
+	while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); }
+
+	/* disable receiver and transmitter */
+	UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
+
+	/* set the parity, stop bits and data size */
+	UART_PUT_MR(port, mode);
+
+	/* set the baud rate */
+	UART_PUT_BRGR(port, quot);
+	UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+	/* restore interrupts */
+	UART_PUT_IER(port, imr);
+
+	/* CTS flow-control and modem-status interrupts */
+	if (UART_ENABLE_MS(port, termios->c_cflag))
+		port->ops->enable_ms(port);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Return string describing the specified port
+ */
+static const char *atmel_type(struct uart_port *port)
+{
+	return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void atmel_release_port(struct uart_port *port)
+{
+	struct platform_device *pdev = to_platform_device(port->dev);
+	int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	release_mem_region(port->mapbase, size);
+
+	if (port->flags & UPF_IOREMAP) {
+		iounmap(port->membase);
+		port->membase = NULL;
+	}
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int atmel_request_port(struct uart_port *port)
+{
+	struct platform_device *pdev = to_platform_device(port->dev);
+	int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	if (!request_mem_region(port->mapbase, size, "atmel_serial"))
+		return -EBUSY;
+
+	if (port->flags & UPF_IOREMAP) {
+		port->membase = ioremap(port->mapbase, size);
+		if (port->membase == NULL) {
+			release_mem_region(port->mapbase, size);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void atmel_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_ATMEL;
+		atmel_request_port(port);
+	}
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	int ret = 0;
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
+		ret = -EINVAL;
+	if (port->irq != ser->irq)
+		ret = -EINVAL;
+	if (ser->io_type != SERIAL_IO_MEM)
+		ret = -EINVAL;
+	if (port->uartclk / 16 != ser->baud_base)
+		ret = -EINVAL;
+	if ((void *)port->mapbase != ser->iomem_base)
+		ret = -EINVAL;
+	if (port->iobase != ser->port)
+		ret = -EINVAL;
+	if (ser->hub6 != 0)
+		ret = -EINVAL;
+	return ret;
+}
+
+static struct uart_ops atmel_pops = {
+	.tx_empty	= atmel_tx_empty,
+	.set_mctrl	= atmel_set_mctrl,
+	.get_mctrl	= atmel_get_mctrl,
+	.stop_tx	= atmel_stop_tx,
+	.start_tx	= atmel_start_tx,
+	.stop_rx	= atmel_stop_rx,
+	.enable_ms	= atmel_enable_ms,
+	.break_ctl	= atmel_break_ctl,
+	.startup	= atmel_startup,
+	.shutdown	= atmel_shutdown,
+	.set_termios	= atmel_set_termios,
+	.type		= atmel_type,
+	.release_port	= atmel_release_port,
+	.request_port	= atmel_request_port,
+	.config_port	= atmel_config_port,
+	.verify_port	= atmel_verify_port,
+	.pm		= atmel_serial_pm,
+};
+
+/*
+ * Configure the port from the platform device resource info.
+ */
+static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev)
+{
+	struct uart_port *port = &atmel_port->uart;
+	struct atmel_uart_data *data = pdev->dev.platform_data;
+
+	port->iotype	= UPIO_MEM;
+	port->flags     = UPF_BOOT_AUTOCONF;
+	port->ops	= &atmel_pops;
+	port->fifosize  = 1;
+	port->line	= pdev->id;
+	port->dev	= &pdev->dev;
+
+	port->mapbase	= pdev->resource[0].start;
+	port->irq	= pdev->resource[1].start;
+
+	if (data->regs)
+		/* Already mapped by setup code */
+		port->membase = data->regs;
+	else {
+		port->flags	|= UPF_IOREMAP;
+		port->membase	= NULL;
+	}
+
+	if (!atmel_port->clk) {		/* for console, the clock could already be configured */
+		atmel_port->clk = clk_get(&pdev->dev, "usart");
+		clk_enable(atmel_port->clk);
+		port->uartclk = clk_get_rate(atmel_port->clk);
+	}
+}
+
+/*
+ * Register board-specific modem-control line handlers.
+ */
+void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
+{
+	if (fns->enable_ms)
+		atmel_pops.enable_ms = fns->enable_ms;
+	if (fns->get_mctrl)
+		atmel_pops.get_mctrl = fns->get_mctrl;
+	if (fns->set_mctrl)
+		atmel_pops.set_mctrl = fns->set_mctrl;
+	atmel_open_hook		= fns->open;
+	atmel_close_hook	= fns->close;
+	atmel_pops.pm		= fns->pm;
+	atmel_pops.set_wake	= fns->set_wake;
+}
+
+
+#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+static void atmel_console_putchar(struct uart_port *port, int ch)
+{
+	while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+		barrier();
+	UART_PUT_CHAR(port, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void atmel_console_write(struct console *co, const char *s, u_int count)
+{
+	struct uart_port *port = &atmel_ports[co->index].uart;
+	unsigned int status, imr;
+
+	/*
+	 *	First, save IMR and then disable interrupts
+	 */
+	imr = UART_GET_IMR(port);	/* get interrupt mask */
+	UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
+
+	uart_console_write(port, s, count, atmel_console_putchar);
+
+	/*
+	 *	Finally, wait for transmitter to become empty
+	 *	and restore IMR
+	 */
+	do {
+		status = UART_GET_CSR(port);
+	} while (!(status & ATMEL_US_TXRDY));
+	UART_PUT_IER(port, imr);	/* set interrupts back the way they were */
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader), try to determine
+ * the current setup.
+ */
+static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+{
+	unsigned int mr, quot;
+
+// TODO: CR is a write-only register
+//	unsigned int cr;
+//
+//	cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN);
+//	if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) {
+//		/* ok, the port was enabled */
+//	}
+
+	mr = UART_GET_MR(port) & ATMEL_US_CHRL;
+	if (mr == ATMEL_US_CHRL_8)
+		*bits = 8;
+	else
+		*bits = 7;
+
+	mr = UART_GET_MR(port) & ATMEL_US_PAR;
+	if (mr == ATMEL_US_PAR_EVEN)
+		*parity = 'e';
+	else if (mr == ATMEL_US_PAR_ODD)
+		*parity = 'o';
+
+	/*
+	 * The serial core only rounds down when matching this to a
+	 * supported baud rate. Make sure we don't end up slightly
+	 * lower than one of those, as it would make us fall through
+	 * to a much lower baud rate than we really want.
+	 */
+	quot = UART_GET_BRGR(port);
+	*baud = port->uartclk / (16 * (quot - 1));
+}
+
+static int __init atmel_console_setup(struct console *co, char *options)
+{
+	struct uart_port *port = &atmel_ports[co->index].uart;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (port->membase == 0)		/* Port not initialized yet - delay setup */
+		return -ENODEV;
+
+	UART_PUT_IDR(port, -1);				/* disable interrupts */
+	UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		atmel_console_get_options(port, &baud, &parity, &bits);
+
+	return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver atmel_uart;
+
+static struct console atmel_console = {
+	.name		= ATMEL_DEVICENAME,
+	.write		= atmel_console_write,
+	.device		= uart_console_device,
+	.setup		= atmel_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &atmel_uart,
+};
+
+#define ATMEL_CONSOLE_DEVICE	&atmel_console
+
+/*
+ * Early console initialization (before VM subsystem initialized).
+ */
+static int __init atmel_console_init(void)
+{
+	if (atmel_default_console_device) {
+		add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL);
+		atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device);
+		register_console(&atmel_console);
+	}
+
+	return 0;
+}
+console_initcall(atmel_console_init);
+
+/*
+ * Late console initialization.
+ */
+static int __init atmel_late_console_init(void)
+{
+	if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED))
+		register_console(&atmel_console);
+
+	return 0;
+}
+core_initcall(atmel_late_console_init);
+
+#else
+#define ATMEL_CONSOLE_DEVICE	NULL
+#endif
+
+static struct uart_driver atmel_uart = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "atmel_serial",
+	.dev_name		= ATMEL_DEVICENAME,
+	.major			= SERIAL_ATMEL_MAJOR,
+	.minor			= MINOR_START,
+	.nr			= ATMEL_MAX_UART,
+	.cons			= ATMEL_CONSOLE_DEVICE,
+};
+
+#ifdef CONFIG_PM
+static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+	if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
+		enable_irq_wake(port->irq);
+	else {
+		disable_irq_wake(port->irq);
+		uart_suspend_port(&atmel_uart, port);
+		atmel_port->suspended = 1;
+	}
+
+	return 0;
+}
+
+static int atmel_serial_resume(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+	if (atmel_port->suspended) {
+		uart_resume_port(&atmel_uart, port);
+		atmel_port->suspended = 0;
+	}
+
+	return 0;
+}
+#else
+#define atmel_serial_suspend NULL
+#define atmel_serial_resume NULL
+#endif
+
+static int __devinit atmel_serial_probe(struct platform_device *pdev)
+{
+	struct atmel_uart_port *port;
+	int ret;
+
+	port = &atmel_ports[pdev->id];
+	atmel_init_port(port, pdev);
+
+	ret = uart_add_one_port(&atmel_uart, &port->uart);
+	if (!ret) {
+		device_init_wakeup(&pdev->dev, 1);
+		platform_set_drvdata(pdev, port);
+	}
+
+	return ret;
+}
+
+static int __devexit atmel_serial_remove(struct platform_device *pdev)
+{
+	struct uart_port *port = platform_get_drvdata(pdev);
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+	int ret = 0;
+
+	clk_disable(atmel_port->clk);
+	clk_put(atmel_port->clk);
+
+	device_init_wakeup(&pdev->dev, 0);
+	platform_set_drvdata(pdev, NULL);
+
+	if (port) {
+		ret = uart_remove_one_port(&atmel_uart, port);
+		kfree(port);
+	}
+
+	return ret;
+}
+
+static struct platform_driver atmel_serial_driver = {
+	.probe		= atmel_serial_probe,
+	.remove		= __devexit_p(atmel_serial_remove),
+	.suspend	= atmel_serial_suspend,
+	.resume		= atmel_serial_resume,
+	.driver		= {
+		.name	= "atmel_usart",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init atmel_serial_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&atmel_uart);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&atmel_serial_driver);
+	if (ret)
+		uart_unregister_driver(&atmel_uart);
+
+	return ret;
+}
+
+static void __exit atmel_serial_exit(void)
+{
+	platform_driver_unregister(&atmel_serial_driver);
+	uart_unregister_driver(&atmel_uart);
+}
+
+module_init(atmel_serial_init);
+module_exit(atmel_serial_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h
new file mode 100644
index 0000000..eced2ad
--- /dev/null
+++ b/drivers/serial/atmel_serial.h
@@ -0,0 +1,123 @@
+/*
+ * drivers/serial/atmel_serial.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * USART registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ATMEL_SERIAL_H
+#define ATMEL_SERIAL_H
+
+#define ATMEL_US_CR		0x00			/* Control Register */
+#define		ATMEL_US_RSTRX		(1 <<  2)		/* Reset Receiver */
+#define		ATMEL_US_RSTTX		(1 <<  3)		/* Reset Transmitter */
+#define		ATMEL_US_RXEN		(1 <<  4)		/* Receiver Enable */
+#define		ATMEL_US_RXDIS		(1 <<  5)		/* Receiver Disable */
+#define		ATMEL_US_TXEN		(1 <<  6)		/* Transmitter Enable */
+#define		ATMEL_US_TXDIS		(1 <<  7)		/* Transmitter Disable */
+#define		ATMEL_US_RSTSTA		(1 <<  8)		/* Reset Status Bits */
+#define		ATMEL_US_STTBRK		(1 <<  9)		/* Start Break */
+#define		ATMEL_US_STPBRK		(1 << 10)		/* Stop Break */
+#define		ATMEL_US_STTTO		(1 << 11)		/* Start Time-out */
+#define		ATMEL_US_SENDA		(1 << 12)		/* Send Address */
+#define		ATMEL_US_RSTIT		(1 << 13)		/* Reset Iterations */
+#define		ATMEL_US_RSTNACK	(1 << 14)		/* Reset Non Acknowledge */
+#define		ATMEL_US_RETTO		(1 << 15)		/* Rearm Time-out */
+#define		ATMEL_US_DTREN		(1 << 16)		/* Data Terminal Ready Enable */
+#define		ATMEL_US_DTRDIS		(1 << 17)		/* Data Terminal Ready Disable */
+#define		ATMEL_US_RTSEN		(1 << 18)		/* Request To Send Enable */
+#define		ATMEL_US_RTSDIS		(1 << 19)		/* Request To Send Disable */
+
+#define ATMEL_US_MR		0x04			/* Mode Register */
+#define		ATMEL_US_USMODE		(0xf <<  0)		/* Mode of the USART */
+#define			ATMEL_US_USMODE_NORMAL		0
+#define			ATMEL_US_USMODE_RS485		1
+#define			ATMEL_US_USMODE_HWHS		2
+#define			ATMEL_US_USMODE_MODEM		3
+#define			ATMEL_US_USMODE_ISO7816_T0	4
+#define			ATMEL_US_USMODE_ISO7816_T1	6
+#define			ATMEL_US_USMODE_IRDA		8
+#define		ATMEL_US_USCLKS		(3   <<  4)		/* Clock Selection */
+#define		ATMEL_US_CHRL		(3   <<  6)		/* Character Length */
+#define			ATMEL_US_CHRL_5			(0 <<  6)
+#define			ATMEL_US_CHRL_6			(1 <<  6)
+#define			ATMEL_US_CHRL_7			(2 <<  6)
+#define			ATMEL_US_CHRL_8			(3 <<  6)
+#define		ATMEL_US_SYNC		(1 <<  8)		/* Synchronous Mode Select */
+#define		ATMEL_US_PAR		(7 <<  9)		/* Parity Type */
+#define			ATMEL_US_PAR_EVEN		(0 <<  9)
+#define			ATMEL_US_PAR_ODD		(1 <<  9)
+#define			ATMEL_US_PAR_SPACE		(2 <<  9)
+#define			ATMEL_US_PAR_MARK		(3 <<  9)
+#define			ATMEL_US_PAR_NONE		(4 <<  9)
+#define			ATMEL_US_PAR_MULTI_DROP		(6 <<  9)
+#define		ATMEL_US_NBSTOP		(3 << 12)		/* Number of Stop Bits */
+#define			ATMEL_US_NBSTOP_1		(0 << 12)
+#define			ATMEL_US_NBSTOP_1_5		(1 << 12)
+#define			ATMEL_US_NBSTOP_2		(2 << 12)
+#define		ATMEL_US_CHMODE		(3 << 14)		/* Channel Mode */
+#define			ATMEL_US_CHMODE_NORMAL		(0 << 14)
+#define			ATMEL_US_CHMODE_ECHO		(1 << 14)
+#define			ATMEL_US_CHMODE_LOC_LOOP	(2 << 14)
+#define			ATMEL_US_CHMODE_REM_LOOP	(3 << 14)
+#define		ATMEL_US_MSBF		(1 << 16)		/* Bit Order */
+#define		ATMEL_US_MODE9		(1 << 17)		/* 9-bit Character Length */
+#define		ATMEL_US_CLKO		(1 << 18)		/* Clock Output Select */
+#define		ATMEL_US_OVER		(1 << 19)		/* Oversampling Mode */
+#define		ATMEL_US_INACK		(1 << 20)		/* Inhibit Non Acknowledge */
+#define		ATMEL_US_DSNACK		(1 << 21)		/* Disable Successive NACK */
+#define		ATMEL_US_MAX_ITER	(7 << 24)		/* Max Iterations */
+#define		ATMEL_US_FILTER		(1 << 28)		/* Infrared Receive Line Filter */
+
+#define ATMEL_US_IER		0x08			/* Interrupt Enable Register */
+#define		ATMEL_US_RXRDY		(1 <<  0)		/* Receiver Ready */
+#define		ATMEL_US_TXRDY		(1 <<  1)		/* Transmitter Ready */
+#define		ATMEL_US_RXBRK		(1 <<  2)		/* Break Received / End of Break */
+#define		ATMEL_US_ENDRX		(1 <<  3)		/* End of Receiver Transfer */
+#define		ATMEL_US_ENDTX		(1 <<  4)		/* End of Transmitter Transfer */
+#define		ATMEL_US_OVRE		(1 <<  5)		/* Overrun Error */
+#define		ATMEL_US_FRAME		(1 <<  6)		/* Framing Error */
+#define		ATMEL_US_PARE		(1 <<  7)		/* Parity Error */
+#define		ATMEL_US_TIMEOUT	(1 <<  8)		/* Receiver Time-out */
+#define		ATMEL_US_TXEMPTY	(1 <<  9)		/* Transmitter Empty */
+#define		ATMEL_US_ITERATION	(1 << 10)		/* Max number of Repetitions Reached */
+#define		ATMEL_US_TXBUFE		(1 << 11)		/* Transmission Buffer Empty */
+#define		ATMEL_US_RXBUFF		(1 << 12)		/* Reception Buffer Full */
+#define		ATMEL_US_NACK		(1 << 13)		/* Non Acknowledge */
+#define		ATMEL_US_RIIC		(1 << 16)		/* Ring Indicator Input Change */
+#define		ATMEL_US_DSRIC		(1 << 17)		/* Data Set Ready Input Change */
+#define		ATMEL_US_DCDIC		(1 << 18)		/* Data Carrier Detect Input Change */
+#define		ATMEL_US_CTSIC		(1 << 19)		/* Clear to Send Input Change */
+#define		ATMEL_US_RI		(1 << 20)		/* RI */
+#define		ATMEL_US_DSR		(1 << 21)		/* DSR */
+#define		ATMEL_US_DCD		(1 << 22)		/* DCD */
+#define		ATMEL_US_CTS		(1 << 23)		/* CTS */
+
+#define ATMEL_US_IDR		0x0c			/* Interrupt Disable Register */
+#define ATMEL_US_IMR		0x10			/* Interrupt Mask Register */
+#define ATMEL_US_CSR		0x14			/* Channel Status Register */
+#define ATMEL_US_RHR		0x18			/* Receiver Holding Register */
+#define ATMEL_US_THR		0x1c			/* Transmitter Holding Register */
+
+#define ATMEL_US_BRGR		0x20			/* Baud Rate Generator Register */
+#define		ATMEL_US_CD		(0xffff << 0)		/* Clock Divider */
+
+#define ATMEL_US_RTOR		0x24			/* Receiver Time-out Register */
+#define		ATMEL_US_TO		(0xffff << 0)		/* Time-out Value */
+
+#define ATMEL_US_TTGR		0x28			/* Transmitter Timeguard Register */
+#define		ATMEL_US_TG		(0xff << 0)		/* Timeguard Value */
+
+#define ATMEL_US_FIDI		0x40			/* FI DI Ratio Register */
+#define ATMEL_US_NER		0x44			/* Number of Errors Register */
+#define ATMEL_US_IF		0x4c			/* IrDA Filter Register */
+
+#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 3b35cb7..a8f894c 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -16,7 +16,6 @@
 #ifndef CPM_UART_H
 #define CPM_UART_H
 
-#include <linux/config.h>
 #include <linux/platform_device.h>
 #include <linux/fs_uart_pd.h>
 
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
index c1adc9e..7502109 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/serial/netx-serial.c
@@ -17,8 +17,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <linux/config.h>
-
 #if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #endif
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index f336ba6..5c025d1 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -20,7 +20,6 @@
 
 #undef DEBUG
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 28643c4..7ee9921 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -10,7 +10,6 @@
  *  Modified to support SH7300(SH-Mobile) SCIF. Takashi Kusuda (Jun 2003).
  *  Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
  */
-#include <linux/config.h>
 #include <linux/serial_core.h>
 #include <asm/io.h>
 
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 5fc1456..20eb6e9 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -13,7 +13,6 @@
 
 //#define DEBUG
 
-#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index aacdceb..a5d2cdf 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -11,7 +11,6 @@
  *
 */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index 16332cc..ebb20ff 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -17,7 +17,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/usb.h>
 #include "usb.h"
 
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 83601d4..64554ac 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -21,7 +21,6 @@
 #define DEBUG 1
 // #define VERBOSE
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index cb2e2a6..0a31520 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -35,7 +35,6 @@
 * via an ELAN U132 adapter.
 *
 */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c
index 4640d10..923e22d 100644
--- a/drivers/usb/input/usbtouchscreen.c
+++ b/drivers/usb/input/usbtouchscreen.c
@@ -35,7 +35,6 @@
 
 //#define DEBUG
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/input.h>
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index bfde82f..fc6cc14 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -20,7 +20,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
index b88a094..c6f2f48 100644
--- a/drivers/usb/misc/ftdi-elan.c
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -35,7 +35,6 @@
 * via an ELAN U132 adapter.
 *
 */
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/init.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index a44124c..a287836 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -36,7 +36,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index fb48fec..bf26c3c 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -47,7 +47,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index c1113d6..5686e21 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -25,7 +25,6 @@
 
 **************************************************************************/
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index b120896..a433cc7 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -1843,7 +1843,7 @@
 		for (i = 0; propnames[i] != NULL; ++i) {
 			pedid = get_property(dp, propnames[i], NULL);
 			if (pedid != NULL) {
-				par->EDID = pedid;
+				par->EDID = (unsigned char *)pedid;
 				NVTRACE("LCD found.\n");
 				return 1;
 			}
diff --git a/fs/Kconfig b/fs/Kconfig
index 68f4561..599de54 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -325,6 +325,7 @@
 	default n
 
 source "fs/xfs/Kconfig"
+source "fs/gfs2/Kconfig"
 
 config OCFS2_FS
 	tristate "OCFS2 file system support"
@@ -995,6 +996,18 @@
 	  To compile this file system support as a module, choose M here: the
 	  module will be called affs.  If unsure, say N.
 
+config ECRYPT_FS
+	tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && KEYS && CRYPTO
+	help
+	  Encrypted filesystem that operates on the VFS layer.  See
+	  <file:Documentation/ecryptfs.txt> to learn more about
+	  eCryptfs.  Userspace components are required and can be
+	  obtained from <http://ecryptfs.sf.net>.
+
+	  To compile this file system support as a module, choose M here: the
+	  module will be called ecryptfs.
+
 config HFS_FS
 	tristate "Apple Macintosh file system support (EXPERIMENTAL)"
 	depends on BLOCK && EXPERIMENTAL
@@ -1983,6 +1996,7 @@
 endif
 
 source "fs/nls/Kconfig"
+source "fs/dlm/Kconfig"
 
 endmenu
 
diff --git a/fs/Makefile b/fs/Makefile
index 819b2a9..df614ea 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -57,6 +57,7 @@
 obj-y				+= devpts/
 
 obj-$(CONFIG_PROFILING)		+= dcookies.o
+obj-$(CONFIG_DLM)		+= dlm/
  
 # Do not add any filesystems before this line
 obj-$(CONFIG_REISERFS_FS)	+= reiserfs/
@@ -75,6 +76,7 @@
 obj-$(CONFIG_ISO9660_FS)	+= isofs/
 obj-$(CONFIG_HFSPLUS_FS)	+= hfsplus/ # Before hfs to find wrapped HFS+
 obj-$(CONFIG_HFS_FS)		+= hfs/
+obj-$(CONFIG_ECRYPT_FS)		+= ecryptfs/
 obj-$(CONFIG_VXFS_FS)		+= freevxfs/
 obj-$(CONFIG_NFS_FS)		+= nfs/
 obj-$(CONFIG_EXPORTFS)		+= exportfs/
@@ -109,3 +111,4 @@
 obj-$(CONFIG_HPPFS)		+= hppfs/
 obj-$(CONFIG_DEBUG_FS)		+= debugfs/
 obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
+obj-$(CONFIG_GFS2_FS)           += gfs2/
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 32b5d62..5bcdaaf 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -29,6 +29,7 @@
 #include <linux/personality.h>
 #include <linux/init.h>
 
+#include <asm/a.out.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 
@@ -194,6 +195,7 @@
 	unsigned long som_entry;
 	struct som_hdr *som_ex;
 	struct som_exec_auxhdr *hpuxhdr;
+	struct files_struct *files;
 
 	/* Get the exec-header */
 	som_ex = (struct som_hdr *) bprm->buf;
@@ -208,15 +210,27 @@
 	size = som_ex->aux_header_size;
 	if (size > SOM_PAGESIZE)
 		goto out;
-	hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL);
+	hpuxhdr = kmalloc(size, GFP_KERNEL);
 	if (!hpuxhdr)
 		goto out;
 
 	retval = kernel_read(bprm->file, som_ex->aux_header_location,
 			(char *) hpuxhdr, size);
+	if (retval != size) {
+		if (retval >= 0)
+			retval = -EIO;
+		goto out_free;
+	}
+
+	files = current->files; /* Refcounted so ok */
+	retval = unshare_files();
 	if (retval < 0)
 		goto out_free;
-#error "Fix security hole before enabling me"
+	if (files == current->files) {
+		put_files_struct(files);
+		files = NULL;
+	}
+
 	retval = get_unused_fd();
 	if (retval < 0)
 		goto out_free;
diff --git a/fs/configfs/item.c b/fs/configfs/item.c
index e07485a..2442120 100644
--- a/fs/configfs/item.c
+++ b/fs/configfs/item.c
@@ -224,4 +224,4 @@
 EXPORT_SYMBOL(config_group_init);
 EXPORT_SYMBOL(config_item_get);
 EXPORT_SYMBOL(config_item_put);
-
+EXPORT_SYMBOL(config_group_find_obj);
diff --git a/fs/dcache.c b/fs/dcache.c
index fc2faa4..2355bdd 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -291,9 +291,9 @@
  * it can be unhashed only if it has no children, or if it is the root
  * of a filesystem.
  *
- * If the inode has a DCACHE_DISCONNECTED alias, then prefer
+ * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
  * any other hashed alias over that one unless @want_discon is set,
- * in which case only return a DCACHE_DISCONNECTED alias.
+ * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
  */
 
 static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
@@ -309,7 +309,8 @@
 		prefetch(next);
 		alias = list_entry(tmp, struct dentry, d_alias);
  		if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
-			if (alias->d_flags & DCACHE_DISCONNECTED)
+			if (IS_ROOT(alias) &&
+			    (alias->d_flags & DCACHE_DISCONNECTED))
 				discon_alias = alias;
 			else if (!want_discon) {
 				__dget_locked(alias);
@@ -1004,7 +1005,7 @@
 {
 	struct dentry *new = NULL;
 
-	if (inode) {
+	if (inode && S_ISDIR(inode->i_mode)) {
 		spin_lock(&dcache_lock);
 		new = __d_find_alias(inode, 1);
 		if (new) {
diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
new file mode 100644
index 0000000..490f85b
--- /dev/null
+++ b/fs/dlm/Kconfig
@@ -0,0 +1,21 @@
+menu "Distributed Lock Manager"
+	depends on INET && EXPERIMENTAL
+
+config DLM
+	tristate "Distributed Lock Manager (DLM)"
+	depends on IPV6 || IPV6=n
+	depends on IP_SCTP
+	select CONFIGFS_FS
+	help
+	A general purpose distributed lock manager for kernel or userspace
+	applications.
+
+config DLM_DEBUG
+	bool "DLM debugging"
+	depends on DLM
+	help
+	Under the debugfs mount point, the name of each lockspace will
+	appear as a file in the "dlm" directory.  The output is the
+	list of resource and locks the local node knows about.
+
+endmenu
diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile
new file mode 100644
index 0000000..1832e02
--- /dev/null
+++ b/fs/dlm/Makefile
@@ -0,0 +1,19 @@
+obj-$(CONFIG_DLM) +=		dlm.o
+dlm-y :=			ast.o \
+				config.o \
+				dir.o \
+				lock.o \
+				lockspace.o \
+				lowcomms.o \
+				main.o \
+				member.o \
+				memory.o \
+				midcomms.o \
+				rcom.o \
+				recover.o \
+				recoverd.o \
+				requestqueue.o \
+				user.o \
+				util.o
+dlm-$(CONFIG_DLM_DEBUG) +=	debug_fs.o
+
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
new file mode 100644
index 0000000..f91d39c
--- /dev/null
+++ b/fs/dlm/ast.c
@@ -0,0 +1,173 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lock.h"
+#include "user.h"
+
+#define WAKE_ASTS  0
+
+static struct list_head		ast_queue;
+static spinlock_t		ast_queue_lock;
+static struct task_struct *	astd_task;
+static unsigned long		astd_wakeflags;
+static struct mutex		astd_running;
+
+
+void dlm_del_ast(struct dlm_lkb *lkb)
+{
+	spin_lock(&ast_queue_lock);
+	if (lkb->lkb_ast_type & (AST_COMP | AST_BAST))
+		list_del(&lkb->lkb_astqueue);
+	spin_unlock(&ast_queue_lock);
+}
+
+void dlm_add_ast(struct dlm_lkb *lkb, int type)
+{
+	if (lkb->lkb_flags & DLM_IFL_USER) {
+		dlm_user_add_ast(lkb, type);
+		return;
+	}
+	DLM_ASSERT(lkb->lkb_astaddr != DLM_FAKE_USER_AST, dlm_print_lkb(lkb););
+
+	spin_lock(&ast_queue_lock);
+	if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+		kref_get(&lkb->lkb_ref);
+		list_add_tail(&lkb->lkb_astqueue, &ast_queue);
+	}
+	lkb->lkb_ast_type |= type;
+	spin_unlock(&ast_queue_lock);
+
+	set_bit(WAKE_ASTS, &astd_wakeflags);
+	wake_up_process(astd_task);
+}
+
+static void process_asts(void)
+{
+	struct dlm_ls *ls = NULL;
+	struct dlm_rsb *r = NULL;
+	struct dlm_lkb *lkb;
+	void (*cast) (long param);
+	void (*bast) (long param, int mode);
+	int type = 0, found, bmode;
+
+	for (;;) {
+		found = 0;
+		spin_lock(&ast_queue_lock);
+		list_for_each_entry(lkb, &ast_queue, lkb_astqueue) {
+			r = lkb->lkb_resource;
+			ls = r->res_ls;
+
+			if (dlm_locking_stopped(ls))
+				continue;
+
+			list_del(&lkb->lkb_astqueue);
+			type = lkb->lkb_ast_type;
+			lkb->lkb_ast_type = 0;
+			found = 1;
+			break;
+		}
+		spin_unlock(&ast_queue_lock);
+
+		if (!found)
+			break;
+
+		cast = lkb->lkb_astaddr;
+		bast = lkb->lkb_bastaddr;
+		bmode = lkb->lkb_bastmode;
+
+		if ((type & AST_COMP) && cast)
+			cast(lkb->lkb_astparam);
+
+		/* FIXME: Is it safe to look at lkb_grmode here
+		   without doing a lock_rsb() ?
+		   Look at other checks in v1 to avoid basts. */
+
+		if ((type & AST_BAST) && bast)
+			if (!dlm_modes_compat(lkb->lkb_grmode, bmode))
+				bast(lkb->lkb_astparam, bmode);
+
+		/* this removes the reference added by dlm_add_ast
+		   and may result in the lkb being freed */
+		dlm_put_lkb(lkb);
+
+		schedule();
+	}
+}
+
+static inline int no_asts(void)
+{
+	int ret;
+
+	spin_lock(&ast_queue_lock);
+	ret = list_empty(&ast_queue);
+	spin_unlock(&ast_queue_lock);
+	return ret;
+}
+
+static int dlm_astd(void *data)
+{
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!test_bit(WAKE_ASTS, &astd_wakeflags))
+			schedule();
+		set_current_state(TASK_RUNNING);
+
+		mutex_lock(&astd_running);
+		if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags))
+			process_asts();
+		mutex_unlock(&astd_running);
+	}
+	return 0;
+}
+
+void dlm_astd_wake(void)
+{
+	if (!no_asts()) {
+		set_bit(WAKE_ASTS, &astd_wakeflags);
+		wake_up_process(astd_task);
+	}
+}
+
+int dlm_astd_start(void)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	INIT_LIST_HEAD(&ast_queue);
+	spin_lock_init(&ast_queue_lock);
+	mutex_init(&astd_running);
+
+	p = kthread_run(dlm_astd, NULL, "dlm_astd");
+	if (IS_ERR(p))
+		error = PTR_ERR(p);
+	else
+		astd_task = p;
+	return error;
+}
+
+void dlm_astd_stop(void)
+{
+	kthread_stop(astd_task);
+}
+
+void dlm_astd_suspend(void)
+{
+	mutex_lock(&astd_running);
+}
+
+void dlm_astd_resume(void)
+{
+	mutex_unlock(&astd_running);
+}
+
diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h
new file mode 100644
index 0000000..6ee276c
--- /dev/null
+++ b/fs/dlm/ast.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __ASTD_DOT_H__
+#define __ASTD_DOT_H__
+
+void dlm_add_ast(struct dlm_lkb *lkb, int type);
+void dlm_del_ast(struct dlm_lkb *lkb);
+
+void dlm_astd_wake(void);
+int dlm_astd_start(void);
+void dlm_astd_stop(void);
+void dlm_astd_suspend(void);
+void dlm_astd_resume(void);
+
+#endif
+
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
new file mode 100644
index 0000000..8855305
--- /dev/null
+++ b/fs/dlm/config.c
@@ -0,0 +1,789 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/configfs.h>
+#include <net/sock.h>
+
+#include "config.h"
+#include "lowcomms.h"
+
+/*
+ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/nodeid
+ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/weight
+ * /config/dlm/<cluster>/comms/<comm>/nodeid
+ * /config/dlm/<cluster>/comms/<comm>/local
+ * /config/dlm/<cluster>/comms/<comm>/addr
+ * The <cluster> level is useless, but I haven't figured out how to avoid it.
+ */
+
+static struct config_group *space_list;
+static struct config_group *comm_list;
+static struct comm *local_comm;
+
+struct clusters;
+struct cluster;
+struct spaces;
+struct space;
+struct comms;
+struct comm;
+struct nodes;
+struct node;
+
+static struct config_group *make_cluster(struct config_group *, const char *);
+static void drop_cluster(struct config_group *, struct config_item *);
+static void release_cluster(struct config_item *);
+static struct config_group *make_space(struct config_group *, const char *);
+static void drop_space(struct config_group *, struct config_item *);
+static void release_space(struct config_item *);
+static struct config_item *make_comm(struct config_group *, const char *);
+static void drop_comm(struct config_group *, struct config_item *);
+static void release_comm(struct config_item *);
+static struct config_item *make_node(struct config_group *, const char *);
+static void drop_node(struct config_group *, struct config_item *);
+static void release_node(struct config_item *);
+
+static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
+			 char *buf);
+static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len);
+static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
+			 char *buf);
+static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len);
+
+static ssize_t comm_nodeid_read(struct comm *cm, char *buf);
+static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t comm_local_read(struct comm *cm, char *buf);
+static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t node_nodeid_read(struct node *nd, char *buf);
+static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len);
+static ssize_t node_weight_read(struct node *nd, char *buf);
+static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len);
+
+enum {
+	COMM_ATTR_NODEID = 0,
+	COMM_ATTR_LOCAL,
+	COMM_ATTR_ADDR,
+};
+
+struct comm_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct comm *, char *);
+	ssize_t (*store)(struct comm *, const char *, size_t);
+};
+
+static struct comm_attribute comm_attr_nodeid = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "nodeid",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = comm_nodeid_read,
+	.store  = comm_nodeid_write,
+};
+
+static struct comm_attribute comm_attr_local = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "local",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = comm_local_read,
+	.store  = comm_local_write,
+};
+
+static struct comm_attribute comm_attr_addr = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "addr",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.store  = comm_addr_write,
+};
+
+static struct configfs_attribute *comm_attrs[] = {
+	[COMM_ATTR_NODEID] = &comm_attr_nodeid.attr,
+	[COMM_ATTR_LOCAL] = &comm_attr_local.attr,
+	[COMM_ATTR_ADDR] = &comm_attr_addr.attr,
+	NULL,
+};
+
+enum {
+	NODE_ATTR_NODEID = 0,
+	NODE_ATTR_WEIGHT,
+};
+
+struct node_attribute {
+	struct configfs_attribute attr;
+	ssize_t (*show)(struct node *, char *);
+	ssize_t (*store)(struct node *, const char *, size_t);
+};
+
+static struct node_attribute node_attr_nodeid = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "nodeid",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = node_nodeid_read,
+	.store  = node_nodeid_write,
+};
+
+static struct node_attribute node_attr_weight = {
+	.attr   = { .ca_owner = THIS_MODULE,
+                    .ca_name = "weight",
+                    .ca_mode = S_IRUGO | S_IWUSR },
+	.show   = node_weight_read,
+	.store  = node_weight_write,
+};
+
+static struct configfs_attribute *node_attrs[] = {
+	[NODE_ATTR_NODEID] = &node_attr_nodeid.attr,
+	[NODE_ATTR_WEIGHT] = &node_attr_weight.attr,
+	NULL,
+};
+
+struct clusters {
+	struct configfs_subsystem subsys;
+};
+
+struct cluster {
+	struct config_group group;
+};
+
+struct spaces {
+	struct config_group ss_group;
+};
+
+struct space {
+	struct config_group group;
+	struct list_head members;
+	struct mutex members_lock;
+	int members_count;
+};
+
+struct comms {
+	struct config_group cs_group;
+};
+
+struct comm {
+	struct config_item item;
+	int nodeid;
+	int local;
+	int addr_count;
+	struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
+};
+
+struct nodes {
+	struct config_group ns_group;
+};
+
+struct node {
+	struct config_item item;
+	struct list_head list; /* space->members */
+	int nodeid;
+	int weight;
+};
+
+static struct configfs_group_operations clusters_ops = {
+	.make_group = make_cluster,
+	.drop_item = drop_cluster,
+};
+
+static struct configfs_item_operations cluster_ops = {
+	.release = release_cluster,
+};
+
+static struct configfs_group_operations spaces_ops = {
+	.make_group = make_space,
+	.drop_item = drop_space,
+};
+
+static struct configfs_item_operations space_ops = {
+	.release = release_space,
+};
+
+static struct configfs_group_operations comms_ops = {
+	.make_item = make_comm,
+	.drop_item = drop_comm,
+};
+
+static struct configfs_item_operations comm_ops = {
+	.release = release_comm,
+	.show_attribute = show_comm,
+	.store_attribute = store_comm,
+};
+
+static struct configfs_group_operations nodes_ops = {
+	.make_item = make_node,
+	.drop_item = drop_node,
+};
+
+static struct configfs_item_operations node_ops = {
+	.release = release_node,
+	.show_attribute = show_node,
+	.store_attribute = store_node,
+};
+
+static struct config_item_type clusters_type = {
+	.ct_group_ops = &clusters_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type cluster_type = {
+	.ct_item_ops = &cluster_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type spaces_type = {
+	.ct_group_ops = &spaces_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type space_type = {
+	.ct_item_ops = &space_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type comms_type = {
+	.ct_group_ops = &comms_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type comm_type = {
+	.ct_item_ops = &comm_ops,
+	.ct_attrs = comm_attrs,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type nodes_type = {
+	.ct_group_ops = &nodes_ops,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type node_type = {
+	.ct_item_ops = &node_ops,
+	.ct_attrs = node_attrs,
+	.ct_owner = THIS_MODULE,
+};
+
+static struct cluster *to_cluster(struct config_item *i)
+{
+	return i ? container_of(to_config_group(i), struct cluster, group):NULL;
+}
+
+static struct space *to_space(struct config_item *i)
+{
+	return i ? container_of(to_config_group(i), struct space, group) : NULL;
+}
+
+static struct comm *to_comm(struct config_item *i)
+{
+	return i ? container_of(i, struct comm, item) : NULL;
+}
+
+static struct node *to_node(struct config_item *i)
+{
+	return i ? container_of(i, struct node, item) : NULL;
+}
+
+static struct config_group *make_cluster(struct config_group *g,
+					 const char *name)
+{
+	struct cluster *cl = NULL;
+	struct spaces *sps = NULL;
+	struct comms *cms = NULL;
+	void *gps = NULL;
+
+	cl = kzalloc(sizeof(struct cluster), GFP_KERNEL);
+	gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
+	sps = kzalloc(sizeof(struct spaces), GFP_KERNEL);
+	cms = kzalloc(sizeof(struct comms), GFP_KERNEL);
+
+	if (!cl || !gps || !sps || !cms)
+		goto fail;
+
+	config_group_init_type_name(&cl->group, name, &cluster_type);
+	config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type);
+	config_group_init_type_name(&cms->cs_group, "comms", &comms_type);
+
+	cl->group.default_groups = gps;
+	cl->group.default_groups[0] = &sps->ss_group;
+	cl->group.default_groups[1] = &cms->cs_group;
+	cl->group.default_groups[2] = NULL;
+
+	space_list = &sps->ss_group;
+	comm_list = &cms->cs_group;
+	return &cl->group;
+
+ fail:
+	kfree(cl);
+	kfree(gps);
+	kfree(sps);
+	kfree(cms);
+	return NULL;
+}
+
+static void drop_cluster(struct config_group *g, struct config_item *i)
+{
+	struct cluster *cl = to_cluster(i);
+	struct config_item *tmp;
+	int j;
+
+	for (j = 0; cl->group.default_groups[j]; j++) {
+		tmp = &cl->group.default_groups[j]->cg_item;
+		cl->group.default_groups[j] = NULL;
+		config_item_put(tmp);
+	}
+
+	space_list = NULL;
+	comm_list = NULL;
+
+	config_item_put(i);
+}
+
+static void release_cluster(struct config_item *i)
+{
+	struct cluster *cl = to_cluster(i);
+	kfree(cl->group.default_groups);
+	kfree(cl);
+}
+
+static struct config_group *make_space(struct config_group *g, const char *name)
+{
+	struct space *sp = NULL;
+	struct nodes *nds = NULL;
+	void *gps = NULL;
+
+	sp = kzalloc(sizeof(struct space), GFP_KERNEL);
+	gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL);
+	nds = kzalloc(sizeof(struct nodes), GFP_KERNEL);
+
+	if (!sp || !gps || !nds)
+		goto fail;
+
+	config_group_init_type_name(&sp->group, name, &space_type);
+	config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
+
+	sp->group.default_groups = gps;
+	sp->group.default_groups[0] = &nds->ns_group;
+	sp->group.default_groups[1] = NULL;
+
+	INIT_LIST_HEAD(&sp->members);
+	mutex_init(&sp->members_lock);
+	sp->members_count = 0;
+	return &sp->group;
+
+ fail:
+	kfree(sp);
+	kfree(gps);
+	kfree(nds);
+	return NULL;
+}
+
+static void drop_space(struct config_group *g, struct config_item *i)
+{
+	struct space *sp = to_space(i);
+	struct config_item *tmp;
+	int j;
+
+	/* assert list_empty(&sp->members) */
+
+	for (j = 0; sp->group.default_groups[j]; j++) {
+		tmp = &sp->group.default_groups[j]->cg_item;
+		sp->group.default_groups[j] = NULL;
+		config_item_put(tmp);
+	}
+
+	config_item_put(i);
+}
+
+static void release_space(struct config_item *i)
+{
+	struct space *sp = to_space(i);
+	kfree(sp->group.default_groups);
+	kfree(sp);
+}
+
+static struct config_item *make_comm(struct config_group *g, const char *name)
+{
+	struct comm *cm;
+
+	cm = kzalloc(sizeof(struct comm), GFP_KERNEL);
+	if (!cm)
+		return NULL;
+
+	config_item_init_type_name(&cm->item, name, &comm_type);
+	cm->nodeid = -1;
+	cm->local = 0;
+	cm->addr_count = 0;
+	return &cm->item;
+}
+
+static void drop_comm(struct config_group *g, struct config_item *i)
+{
+	struct comm *cm = to_comm(i);
+	if (local_comm == cm)
+		local_comm = NULL;
+	dlm_lowcomms_close(cm->nodeid);
+	while (cm->addr_count--)
+		kfree(cm->addr[cm->addr_count]);
+	config_item_put(i);
+}
+
+static void release_comm(struct config_item *i)
+{
+	struct comm *cm = to_comm(i);
+	kfree(cm);
+}
+
+static struct config_item *make_node(struct config_group *g, const char *name)
+{
+	struct space *sp = to_space(g->cg_item.ci_parent);
+	struct node *nd;
+
+	nd = kzalloc(sizeof(struct node), GFP_KERNEL);
+	if (!nd)
+		return NULL;
+
+	config_item_init_type_name(&nd->item, name, &node_type);
+	nd->nodeid = -1;
+	nd->weight = 1;  /* default weight of 1 if none is set */
+
+	mutex_lock(&sp->members_lock);
+	list_add(&nd->list, &sp->members);
+	sp->members_count++;
+	mutex_unlock(&sp->members_lock);
+
+	return &nd->item;
+}
+
+static void drop_node(struct config_group *g, struct config_item *i)
+{
+	struct space *sp = to_space(g->cg_item.ci_parent);
+	struct node *nd = to_node(i);
+
+	mutex_lock(&sp->members_lock);
+	list_del(&nd->list);
+	sp->members_count--;
+	mutex_unlock(&sp->members_lock);
+
+	config_item_put(i);
+}
+
+static void release_node(struct config_item *i)
+{
+	struct node *nd = to_node(i);
+	kfree(nd);
+}
+
+static struct clusters clusters_root = {
+	.subsys = {
+		.su_group = {
+			.cg_item = {
+				.ci_namebuf = "dlm",
+				.ci_type = &clusters_type,
+			},
+		},
+	},
+};
+
+int dlm_config_init(void)
+{
+	config_group_init(&clusters_root.subsys.su_group);
+	init_MUTEX(&clusters_root.subsys.su_sem);
+	return configfs_register_subsystem(&clusters_root.subsys);
+}
+
+void dlm_config_exit(void)
+{
+	configfs_unregister_subsystem(&clusters_root.subsys);
+}
+
+/*
+ * Functions for user space to read/write attributes
+ */
+
+static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
+			 char *buf)
+{
+	struct comm *cm = to_comm(i);
+	struct comm_attribute *cma =
+			container_of(a, struct comm_attribute, attr);
+	return cma->show ? cma->show(cm, buf) : 0;
+}
+
+static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len)
+{
+	struct comm *cm = to_comm(i);
+	struct comm_attribute *cma =
+		container_of(a, struct comm_attribute, attr);
+	return cma->store ? cma->store(cm, buf, len) : -EINVAL;
+}
+
+static ssize_t comm_nodeid_read(struct comm *cm, char *buf)
+{
+	return sprintf(buf, "%d\n", cm->nodeid);
+}
+
+static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len)
+{
+	cm->nodeid = simple_strtol(buf, NULL, 0);
+	return len;
+}
+
+static ssize_t comm_local_read(struct comm *cm, char *buf)
+{
+	return sprintf(buf, "%d\n", cm->local);
+}
+
+static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len)
+{
+	cm->local= simple_strtol(buf, NULL, 0);
+	if (cm->local && !local_comm)
+		local_comm = cm;
+	return len;
+}
+
+static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len)
+{
+	struct sockaddr_storage *addr;
+
+	if (len != sizeof(struct sockaddr_storage))
+		return -EINVAL;
+
+	if (cm->addr_count >= DLM_MAX_ADDR_COUNT)
+		return -ENOSPC;
+
+	addr = kzalloc(sizeof(*addr), GFP_KERNEL);
+	if (!addr)
+		return -ENOMEM;
+
+	memcpy(addr, buf, len);
+	cm->addr[cm->addr_count++] = addr;
+	return len;
+}
+
+static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
+			 char *buf)
+{
+	struct node *nd = to_node(i);
+	struct node_attribute *nda =
+			container_of(a, struct node_attribute, attr);
+	return nda->show ? nda->show(nd, buf) : 0;
+}
+
+static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
+			  const char *buf, size_t len)
+{
+	struct node *nd = to_node(i);
+	struct node_attribute *nda =
+		container_of(a, struct node_attribute, attr);
+	return nda->store ? nda->store(nd, buf, len) : -EINVAL;
+}
+
+static ssize_t node_nodeid_read(struct node *nd, char *buf)
+{
+	return sprintf(buf, "%d\n", nd->nodeid);
+}
+
+static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len)
+{
+	nd->nodeid = simple_strtol(buf, NULL, 0);
+	return len;
+}
+
+static ssize_t node_weight_read(struct node *nd, char *buf)
+{
+	return sprintf(buf, "%d\n", nd->weight);
+}
+
+static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len)
+{
+	nd->weight = simple_strtol(buf, NULL, 0);
+	return len;
+}
+
+/*
+ * Functions for the dlm to get the info that's been configured
+ */
+
+static struct space *get_space(char *name)
+{
+	if (!space_list)
+		return NULL;
+	return to_space(config_group_find_obj(space_list, name));
+}
+
+static void put_space(struct space *sp)
+{
+	config_item_put(&sp->group.cg_item);
+}
+
+static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr)
+{
+	struct config_item *i;
+	struct comm *cm = NULL;
+	int found = 0;
+
+	if (!comm_list)
+		return NULL;
+
+	down(&clusters_root.subsys.su_sem);
+
+	list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
+		cm = to_comm(i);
+
+		if (nodeid) {
+			if (cm->nodeid != nodeid)
+				continue;
+			found = 1;
+			break;
+		} else {
+			if (!cm->addr_count ||
+			    memcmp(cm->addr[0], addr, sizeof(*addr)))
+				continue;
+			found = 1;
+			break;
+		}
+	}
+	up(&clusters_root.subsys.su_sem);
+
+	if (found)
+		config_item_get(i);
+	else
+		cm = NULL;
+	return cm;
+}
+
+static void put_comm(struct comm *cm)
+{
+	config_item_put(&cm->item);
+}
+
+/* caller must free mem */
+int dlm_nodeid_list(char *lsname, int **ids_out)
+{
+	struct space *sp;
+	struct node *nd;
+	int i = 0, rv = 0;
+	int *ids;
+
+	sp = get_space(lsname);
+	if (!sp)
+		return -EEXIST;
+
+	mutex_lock(&sp->members_lock);
+	if (!sp->members_count) {
+		rv = 0;
+		goto out;
+	}
+
+	ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL);
+	if (!ids) {
+		rv = -ENOMEM;
+		goto out;
+	}
+
+	rv = sp->members_count;
+	list_for_each_entry(nd, &sp->members, list)
+		ids[i++] = nd->nodeid;
+
+	if (rv != i)
+		printk("bad nodeid count %d %d\n", rv, i);
+
+	*ids_out = ids;
+ out:
+	mutex_unlock(&sp->members_lock);
+	put_space(sp);
+	return rv;
+}
+
+int dlm_node_weight(char *lsname, int nodeid)
+{
+	struct space *sp;
+	struct node *nd;
+	int w = -EEXIST;
+
+	sp = get_space(lsname);
+	if (!sp)
+		goto out;
+
+	mutex_lock(&sp->members_lock);
+	list_for_each_entry(nd, &sp->members, list) {
+		if (nd->nodeid != nodeid)
+			continue;
+		w = nd->weight;
+		break;
+	}
+	mutex_unlock(&sp->members_lock);
+	put_space(sp);
+ out:
+	return w;
+}
+
+int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)
+{
+	struct comm *cm = get_comm(nodeid, NULL);
+	if (!cm)
+		return -EEXIST;
+	if (!cm->addr_count)
+		return -ENOENT;
+	memcpy(addr, cm->addr[0], sizeof(*addr));
+	put_comm(cm);
+	return 0;
+}
+
+int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
+{
+	struct comm *cm = get_comm(0, addr);
+	if (!cm)
+		return -EEXIST;
+	*nodeid = cm->nodeid;
+	put_comm(cm);
+	return 0;
+}
+
+int dlm_our_nodeid(void)
+{
+	return local_comm ? local_comm->nodeid : 0;
+}
+
+/* num 0 is first addr, num 1 is second addr */
+int dlm_our_addr(struct sockaddr_storage *addr, int num)
+{
+	if (!local_comm)
+		return -1;
+	if (num + 1 > local_comm->addr_count)
+		return -1;
+	memcpy(addr, local_comm->addr[num], sizeof(*addr));
+	return 0;
+}
+
+/* Config file defaults */
+#define DEFAULT_TCP_PORT       21064
+#define DEFAULT_BUFFER_SIZE     4096
+#define DEFAULT_RSBTBL_SIZE      256
+#define DEFAULT_LKBTBL_SIZE     1024
+#define DEFAULT_DIRTBL_SIZE      512
+#define DEFAULT_RECOVER_TIMER      5
+#define DEFAULT_TOSS_SECS         10
+#define DEFAULT_SCAN_SECS          5
+
+struct dlm_config_info dlm_config = {
+	.tcp_port = DEFAULT_TCP_PORT,
+	.buffer_size = DEFAULT_BUFFER_SIZE,
+	.rsbtbl_size = DEFAULT_RSBTBL_SIZE,
+	.lkbtbl_size = DEFAULT_LKBTBL_SIZE,
+	.dirtbl_size = DEFAULT_DIRTBL_SIZE,
+	.recover_timer = DEFAULT_RECOVER_TIMER,
+	.toss_secs = DEFAULT_TOSS_SECS,
+	.scan_secs = DEFAULT_SCAN_SECS
+};
+
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
new file mode 100644
index 0000000..9da7839
--- /dev/null
+++ b/fs/dlm/config.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __CONFIG_DOT_H__
+#define __CONFIG_DOT_H__
+
+#define DLM_MAX_ADDR_COUNT 3
+
+struct dlm_config_info {
+	int tcp_port;
+	int buffer_size;
+	int rsbtbl_size;
+	int lkbtbl_size;
+	int dirtbl_size;
+	int recover_timer;
+	int toss_secs;
+	int scan_secs;
+};
+
+extern struct dlm_config_info dlm_config;
+
+int dlm_config_init(void);
+void dlm_config_exit(void);
+int dlm_node_weight(char *lsname, int nodeid);
+int dlm_nodeid_list(char *lsname, int **ids_out);
+int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
+int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
+int dlm_our_nodeid(void);
+int dlm_our_addr(struct sockaddr_storage *addr, int num);
+
+#endif				/* __CONFIG_DOT_H__ */
+
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
new file mode 100644
index 0000000..ca94a83
--- /dev/null
+++ b/fs/dlm/debug_fs.c
@@ -0,0 +1,387 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+
+#include "dlm_internal.h"
+
+#define DLM_DEBUG_BUF_LEN 4096
+static char debug_buf[DLM_DEBUG_BUF_LEN];
+static struct mutex debug_buf_lock;
+
+static struct dentry *dlm_root;
+
+struct rsb_iter {
+	int entry;
+	struct dlm_ls *ls;
+	struct list_head *next;
+	struct dlm_rsb *rsb;
+};
+
+/*
+ * dump all rsb's in the lockspace hash table
+ */
+
+static char *print_lockmode(int mode)
+{
+	switch (mode) {
+	case DLM_LOCK_IV:
+		return "--";
+	case DLM_LOCK_NL:
+		return "NL";
+	case DLM_LOCK_CR:
+		return "CR";
+	case DLM_LOCK_CW:
+		return "CW";
+	case DLM_LOCK_PR:
+		return "PR";
+	case DLM_LOCK_PW:
+		return "PW";
+	case DLM_LOCK_EX:
+		return "EX";
+	default:
+		return "??";
+	}
+}
+
+static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
+		       struct dlm_rsb *res)
+{
+	seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
+
+	if (lkb->lkb_status == DLM_LKSTS_CONVERT
+	    || lkb->lkb_status == DLM_LKSTS_WAITING)
+		seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
+
+	if (lkb->lkb_nodeid) {
+		if (lkb->lkb_nodeid != res->res_nodeid)
+			seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
+				   lkb->lkb_remid);
+		else
+			seq_printf(s, " Master:     %08x", lkb->lkb_remid);
+	}
+
+	if (lkb->lkb_wait_type)
+		seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
+
+	seq_printf(s, "\n");
+}
+
+static int print_resource(struct dlm_rsb *res, struct seq_file *s)
+{
+	struct dlm_lkb *lkb;
+	int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
+
+	seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
+	for (i = 0; i < res->res_length; i++) {
+		if (isprint(res->res_name[i]))
+			seq_printf(s, "%c", res->res_name[i]);
+		else
+			seq_printf(s, "%c", '.');
+	}
+	if (res->res_nodeid > 0)
+		seq_printf(s, "\"  \nLocal Copy, Master is node %d\n",
+			   res->res_nodeid);
+	else if (res->res_nodeid == 0)
+		seq_printf(s, "\"  \nMaster Copy\n");
+	else if (res->res_nodeid == -1)
+		seq_printf(s, "\"  \nLooking up master (lkid %x)\n",
+			   res->res_first_lkid);
+	else
+		seq_printf(s, "\"  \nInvalid master %d\n", res->res_nodeid);
+
+	/* Print the LVB: */
+	if (res->res_lvbptr) {
+		seq_printf(s, "LVB: ");
+		for (i = 0; i < lvblen; i++) {
+			if (i == lvblen / 2)
+				seq_printf(s, "\n     ");
+			seq_printf(s, "%02x ",
+				   (unsigned char) res->res_lvbptr[i]);
+		}
+		if (rsb_flag(res, RSB_VALNOTVALID))
+			seq_printf(s, " (INVALID)");
+		seq_printf(s, "\n");
+	}
+
+	root_list = !list_empty(&res->res_root_list);
+	recover_list = !list_empty(&res->res_recover_list);
+
+	if (root_list || recover_list) {
+		seq_printf(s, "Recovery: root %d recover %d flags %lx "
+			   "count %d\n", root_list, recover_list,
+			   res->res_flags, res->res_recover_locks_count);
+	}
+
+	/* Print the locks attached to this resource */
+	seq_printf(s, "Granted Queue\n");
+	list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
+		print_lock(s, lkb, res);
+
+	seq_printf(s, "Conversion Queue\n");
+	list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
+		print_lock(s, lkb, res);
+
+	seq_printf(s, "Waiting Queue\n");
+	list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
+		print_lock(s, lkb, res);
+
+	if (list_empty(&res->res_lookup))
+		goto out;
+
+	seq_printf(s, "Lookup Queue\n");
+	list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
+		seq_printf(s, "%08x %s", lkb->lkb_id,
+			   print_lockmode(lkb->lkb_rqmode));
+		if (lkb->lkb_wait_type)
+			seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
+		seq_printf(s, "\n");
+	}
+ out:
+	return 0;
+}
+
+static int rsb_iter_next(struct rsb_iter *ri)
+{
+	struct dlm_ls *ls = ri->ls;
+	int i;
+
+	if (!ri->next) {
+ top:
+		/* Find the next non-empty hash bucket */
+		for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
+			read_lock(&ls->ls_rsbtbl[i].lock);
+			if (!list_empty(&ls->ls_rsbtbl[i].list)) {
+				ri->next = ls->ls_rsbtbl[i].list.next;
+				read_unlock(&ls->ls_rsbtbl[i].lock);
+				break;
+			}
+			read_unlock(&ls->ls_rsbtbl[i].lock);
+                }
+		ri->entry = i;
+
+		if (ri->entry >= ls->ls_rsbtbl_size)
+			return 1;
+	} else {
+		i = ri->entry;
+		read_lock(&ls->ls_rsbtbl[i].lock);
+		ri->next = ri->next->next;
+		if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
+			/* End of list - move to next bucket */
+			ri->next = NULL;
+			ri->entry++;
+			read_unlock(&ls->ls_rsbtbl[i].lock);
+			goto top;
+                }
+		read_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+	ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
+
+	return 0;
+}
+
+static void rsb_iter_free(struct rsb_iter *ri)
+{
+	kfree(ri);
+}
+
+static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
+{
+	struct rsb_iter *ri;
+
+	ri = kmalloc(sizeof *ri, GFP_KERNEL);
+	if (!ri)
+		return NULL;
+
+	ri->ls = ls;
+	ri->entry = 0;
+	ri->next = NULL;
+
+	if (rsb_iter_next(ri)) {
+		rsb_iter_free(ri);
+		return NULL;
+	}
+
+	return ri;
+}
+
+static void *rsb_seq_start(struct seq_file *file, loff_t *pos)
+{
+	struct rsb_iter *ri;
+	loff_t n = *pos;
+
+	ri = rsb_iter_init(file->private);
+	if (!ri)
+		return NULL;
+
+	while (n--) {
+		if (rsb_iter_next(ri)) {
+			rsb_iter_free(ri);
+			return NULL;
+		}
+	}
+
+	return ri;
+}
+
+static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
+{
+	struct rsb_iter *ri = iter_ptr;
+
+	(*pos)++;
+
+	if (rsb_iter_next(ri)) {
+		rsb_iter_free(ri);
+		return NULL;
+	}
+
+	return ri;
+}
+
+static void rsb_seq_stop(struct seq_file *file, void *iter_ptr)
+{
+	/* nothing for now */
+}
+
+static int rsb_seq_show(struct seq_file *file, void *iter_ptr)
+{
+	struct rsb_iter *ri = iter_ptr;
+
+	print_resource(ri->rsb, file);
+
+	return 0;
+}
+
+static struct seq_operations rsb_seq_ops = {
+	.start = rsb_seq_start,
+	.next  = rsb_seq_next,
+	.stop  = rsb_seq_stop,
+	.show  = rsb_seq_show,
+};
+
+static int rsb_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int ret;
+
+	ret = seq_open(file, &rsb_seq_ops);
+	if (ret)
+		return ret;
+
+	seq = file->private_data;
+	seq->private = inode->i_private;
+
+	return 0;
+}
+
+static struct file_operations rsb_fops = {
+	.owner   = THIS_MODULE,
+	.open    = rsb_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
+
+/*
+ * dump lkb's on the ls_waiters list
+ */
+
+static int waiters_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t waiters_read(struct file *file, char __user *userbuf,
+			    size_t count, loff_t *ppos)
+{
+	struct dlm_ls *ls = file->private_data;
+	struct dlm_lkb *lkb;
+	size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;
+
+	mutex_lock(&debug_buf_lock);
+	mutex_lock(&ls->ls_waiters_mutex);
+	memset(debug_buf, 0, sizeof(debug_buf));
+
+	list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+		ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
+			       lkb->lkb_id, lkb->lkb_wait_type,
+			       lkb->lkb_nodeid, lkb->lkb_resource->res_name);
+		if (ret >= len - pos)
+			break;
+		pos += ret;
+	}
+	mutex_unlock(&ls->ls_waiters_mutex);
+
+	rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
+	mutex_unlock(&debug_buf_lock);
+	return rv;
+}
+
+static struct file_operations waiters_fops = {
+	.owner   = THIS_MODULE,
+	.open    = waiters_open,
+	.read    = waiters_read
+};
+
+int dlm_create_debug_file(struct dlm_ls *ls)
+{
+	char name[DLM_LOCKSPACE_LEN+8];
+
+	ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
+						      S_IFREG | S_IRUGO,
+						      dlm_root,
+						      ls,
+						      &rsb_fops);
+	if (!ls->ls_debug_rsb_dentry)
+		return -ENOMEM;
+
+	memset(name, 0, sizeof(name));
+	snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name);
+
+	ls->ls_debug_waiters_dentry = debugfs_create_file(name,
+							  S_IFREG | S_IRUGO,
+							  dlm_root,
+							  ls,
+							  &waiters_fops);
+	if (!ls->ls_debug_waiters_dentry) {
+		debugfs_remove(ls->ls_debug_rsb_dentry);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+void dlm_delete_debug_file(struct dlm_ls *ls)
+{
+	if (ls->ls_debug_rsb_dentry)
+		debugfs_remove(ls->ls_debug_rsb_dentry);
+	if (ls->ls_debug_waiters_dentry)
+		debugfs_remove(ls->ls_debug_waiters_dentry);
+}
+
+int dlm_register_debugfs(void)
+{
+	mutex_init(&debug_buf_lock);
+	dlm_root = debugfs_create_dir("dlm", NULL);
+	return dlm_root ? 0 : -ENOMEM;
+}
+
+void dlm_unregister_debugfs(void)
+{
+	debugfs_remove(dlm_root);
+}
+
diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c
new file mode 100644
index 0000000..4675455
--- /dev/null
+++ b/fs/dlm/dir.c
@@ -0,0 +1,423 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "lowcomms.h"
+#include "rcom.h"
+#include "config.h"
+#include "memory.h"
+#include "recover.h"
+#include "util.h"
+#include "lock.h"
+#include "dir.h"
+
+
+static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)
+{
+	spin_lock(&ls->ls_recover_list_lock);
+	list_add(&de->list, &ls->ls_recover_list);
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
+{
+	int found = 0;
+	struct dlm_direntry *de;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	list_for_each_entry(de, &ls->ls_recover_list, list) {
+		if (de->length == len) {
+			list_del(&de->list);
+			de->master_nodeid = 0;
+			memset(de->name, 0, len);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+
+	if (!found)
+		de = allocate_direntry(ls, len);
+	return de;
+}
+
+void dlm_clear_free_entries(struct dlm_ls *ls)
+{
+	struct dlm_direntry *de;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	while (!list_empty(&ls->ls_recover_list)) {
+		de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,
+				list);
+		list_del(&de->list);
+		free_direntry(de);
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+/*
+ * We use the upper 16 bits of the hash value to select the directory node.
+ * Low bits are used for distribution of rsb's among hash buckets on each node.
+ *
+ * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of
+ * num_nodes to the hash value.  This value in the desired range is used as an
+ * offset into the sorted list of nodeid's to give the particular nodeid.
+ */
+
+int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
+{
+	struct list_head *tmp;
+	struct dlm_member *memb = NULL;
+	uint32_t node, n = 0;
+	int nodeid;
+
+	if (ls->ls_num_nodes == 1) {
+		nodeid = dlm_our_nodeid();
+		goto out;
+	}
+
+	if (ls->ls_node_array) {
+		node = (hash >> 16) % ls->ls_total_weight;
+		nodeid = ls->ls_node_array[node];
+		goto out;
+	}
+
+	/* make_member_array() failed to kmalloc ls_node_array... */
+
+	node = (hash >> 16) % ls->ls_num_nodes;
+
+	list_for_each(tmp, &ls->ls_nodes) {
+		if (n++ != node)
+			continue;
+		memb = list_entry(tmp, struct dlm_member, list);
+		break;
+	}
+
+	DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n",
+				 ls->ls_num_nodes, n, node););
+	nodeid = memb->nodeid;
+ out:
+	return nodeid;
+}
+
+int dlm_dir_nodeid(struct dlm_rsb *r)
+{
+	return dlm_hash2nodeid(r->res_ls, r->res_hash);
+}
+
+static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)
+{
+	uint32_t val;
+
+	val = jhash(name, len, 0);
+	val &= (ls->ls_dirtbl_size - 1);
+
+	return val;
+}
+
+static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)
+{
+	uint32_t bucket;
+
+	bucket = dir_hash(ls, de->name, de->length);
+	list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
+}
+
+static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,
+					  int namelen, uint32_t bucket)
+{
+	struct dlm_direntry *de;
+
+	list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) {
+		if (de->length == namelen && !memcmp(name, de->name, namelen))
+			goto out;
+	}
+	de = NULL;
+ out:
+	return de;
+}
+
+void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)
+{
+	struct dlm_direntry *de;
+	uint32_t bucket;
+
+	bucket = dir_hash(ls, name, namelen);
+
+	write_lock(&ls->ls_dirtbl[bucket].lock);
+
+	de = search_bucket(ls, name, namelen, bucket);
+
+	if (!de) {
+		log_error(ls, "remove fr %u none", nodeid);
+		goto out;
+	}
+
+	if (de->master_nodeid != nodeid) {
+		log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid);
+		goto out;
+	}
+
+	list_del(&de->list);
+	free_direntry(de);
+ out:
+	write_unlock(&ls->ls_dirtbl[bucket].lock);
+}
+
+void dlm_dir_clear(struct dlm_ls *ls)
+{
+	struct list_head *head;
+	struct dlm_direntry *de;
+	int i;
+
+	DLM_ASSERT(list_empty(&ls->ls_recover_list), );
+
+	for (i = 0; i < ls->ls_dirtbl_size; i++) {
+		write_lock(&ls->ls_dirtbl[i].lock);
+		head = &ls->ls_dirtbl[i].list;
+		while (!list_empty(head)) {
+			de = list_entry(head->next, struct dlm_direntry, list);
+			list_del(&de->list);
+			put_free_de(ls, de);
+		}
+		write_unlock(&ls->ls_dirtbl[i].lock);
+	}
+}
+
+int dlm_recover_directory(struct dlm_ls *ls)
+{
+	struct dlm_member *memb;
+	struct dlm_direntry *de;
+	char *b, *last_name = NULL;
+	int error = -ENOMEM, last_len, count = 0;
+	uint16_t namelen;
+
+	log_debug(ls, "dlm_recover_directory");
+
+	if (dlm_no_directory(ls))
+		goto out_status;
+
+	dlm_dir_clear(ls);
+
+	last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
+	if (!last_name)
+		goto out;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		memset(last_name, 0, DLM_RESNAME_MAXLEN);
+		last_len = 0;
+
+		for (;;) {
+			error = dlm_recovery_stopped(ls);
+			if (error)
+				goto out_free;
+
+			error = dlm_rcom_names(ls, memb->nodeid,
+					       last_name, last_len);
+			if (error)
+				goto out_free;
+
+			schedule();
+
+			/*
+			 * pick namelen/name pairs out of received buffer
+			 */
+
+			b = ls->ls_recover_buf + sizeof(struct dlm_rcom);
+
+			for (;;) {
+				memcpy(&namelen, b, sizeof(uint16_t));
+				namelen = be16_to_cpu(namelen);
+				b += sizeof(uint16_t);
+
+				/* namelen of 0xFFFFF marks end of names for
+				   this node; namelen of 0 marks end of the
+				   buffer */
+
+				if (namelen == 0xFFFF)
+					goto done;
+				if (!namelen)
+					break;
+
+				error = -ENOMEM;
+				de = get_free_de(ls, namelen);
+				if (!de)
+					goto out_free;
+
+				de->master_nodeid = memb->nodeid;
+				de->length = namelen;
+				last_len = namelen;
+				memcpy(de->name, b, namelen);
+				memcpy(last_name, b, namelen);
+				b += namelen;
+
+				add_entry_to_hash(ls, de);
+				count++;
+			}
+		}
+         done:
+		;
+	}
+
+ out_status:
+	error = 0;
+	dlm_set_recover_status(ls, DLM_RS_DIR);
+	log_debug(ls, "dlm_recover_directory %d entries", count);
+ out_free:
+	kfree(last_name);
+ out:
+	dlm_clear_free_entries(ls);
+	return error;
+}
+
+static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
+		     int namelen, int *r_nodeid)
+{
+	struct dlm_direntry *de, *tmp;
+	uint32_t bucket;
+
+	bucket = dir_hash(ls, name, namelen);
+
+	write_lock(&ls->ls_dirtbl[bucket].lock);
+	de = search_bucket(ls, name, namelen, bucket);
+	if (de) {
+		*r_nodeid = de->master_nodeid;
+		write_unlock(&ls->ls_dirtbl[bucket].lock);
+		if (*r_nodeid == nodeid)
+			return -EEXIST;
+		return 0;
+	}
+
+	write_unlock(&ls->ls_dirtbl[bucket].lock);
+
+	de = allocate_direntry(ls, namelen);
+	if (!de)
+		return -ENOMEM;
+
+	de->master_nodeid = nodeid;
+	de->length = namelen;
+	memcpy(de->name, name, namelen);
+
+	write_lock(&ls->ls_dirtbl[bucket].lock);
+	tmp = search_bucket(ls, name, namelen, bucket);
+	if (tmp) {
+		free_direntry(de);
+		de = tmp;
+	} else {
+		list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
+	}
+	*r_nodeid = de->master_nodeid;
+	write_unlock(&ls->ls_dirtbl[bucket].lock);
+	return 0;
+}
+
+int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
+		   int *r_nodeid)
+{
+	return get_entry(ls, nodeid, name, namelen, r_nodeid);
+}
+
+/* Copy the names of master rsb's into the buffer provided.
+   Only select names whose dir node is the given nodeid. */
+
+void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
+ 			   char *outbuf, int outlen, int nodeid)
+{
+	struct list_head *list;
+	struct dlm_rsb *start_r = NULL, *r = NULL;
+	int offset = 0, start_namelen, error, dir_nodeid;
+	char *start_name;
+	uint16_t be_namelen;
+
+	/*
+	 * Find the rsb where we left off (or start again)
+	 */
+
+	start_namelen = inlen;
+	start_name = inbuf;
+
+	if (start_namelen > 1) {
+		/*
+		 * We could also use a find_rsb_root() function here that
+		 * searched the ls_root_list.
+		 */
+		error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER,
+				     &start_r);
+		DLM_ASSERT(!error && start_r,
+			   printk("error %d\n", error););
+		DLM_ASSERT(!list_empty(&start_r->res_root_list),
+			   dlm_print_rsb(start_r););
+		dlm_put_rsb(start_r);
+	}
+
+	/*
+	 * Send rsb names for rsb's we're master of and whose directory node
+	 * matches the requesting node.
+	 */
+
+	down_read(&ls->ls_root_sem);
+	if (start_r)
+		list = start_r->res_root_list.next;
+	else
+		list = ls->ls_root_list.next;
+
+	for (offset = 0; list != &ls->ls_root_list; list = list->next) {
+		r = list_entry(list, struct dlm_rsb, res_root_list);
+		if (r->res_nodeid)
+			continue;
+
+		dir_nodeid = dlm_dir_nodeid(r);
+		if (dir_nodeid != nodeid)
+			continue;
+
+		/*
+		 * The block ends when we can't fit the following in the
+		 * remaining buffer space:
+		 * namelen (uint16_t) +
+		 * name (r->res_length) +
+		 * end-of-block record 0x0000 (uint16_t)
+		 */
+
+		if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
+			/* Write end-of-block record */
+			be_namelen = 0;
+			memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+			offset += sizeof(uint16_t);
+			goto out;
+		}
+
+		be_namelen = cpu_to_be16(r->res_length);
+		memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+		offset += sizeof(uint16_t);
+		memcpy(outbuf + offset, r->res_name, r->res_length);
+		offset += r->res_length;
+	}
+
+	/*
+	 * If we've reached the end of the list (and there's room) write a
+	 * terminating record.
+	 */
+
+	if ((list == &ls->ls_root_list) &&
+	    (offset + sizeof(uint16_t) <= outlen)) {
+		be_namelen = 0xFFFF;
+		memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+		offset += sizeof(uint16_t);
+	}
+
+ out:
+	up_read(&ls->ls_root_sem);
+}
+
diff --git a/fs/dlm/dir.h b/fs/dlm/dir.h
new file mode 100644
index 0000000..0b0eb12
--- /dev/null
+++ b/fs/dlm/dir.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DIR_DOT_H__
+#define __DIR_DOT_H__
+
+
+int dlm_dir_nodeid(struct dlm_rsb *rsb);
+int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash);
+void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len);
+void dlm_dir_clear(struct dlm_ls *ls);
+void dlm_clear_free_entries(struct dlm_ls *ls);
+int dlm_recover_directory(struct dlm_ls *ls);
+int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
+	int *r_nodeid);
+void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
+	char *outbuf, int outlen, int nodeid);
+
+#endif				/* __DIR_DOT_H__ */
+
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
new file mode 100644
index 0000000..1e5cd67
--- /dev/null
+++ b/fs/dlm/dlm_internal.h
@@ -0,0 +1,543 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DLM_INTERNAL_DOT_H__
+#define __DLM_INTERNAL_DOT_H__
+
+/*
+ * This is the main header file to be included in each DLM source file.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/socket.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/kref.h>
+#include <linux/kernel.h>
+#include <linux/jhash.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/dlm.h>
+
+#define DLM_LOCKSPACE_LEN	64
+
+/* Size of the temp buffer midcomms allocates on the stack.
+   We try to make this large enough so most messages fit.
+   FIXME: should sctp make this unnecessary? */
+
+#define DLM_INBUF_LEN		148
+
+struct dlm_ls;
+struct dlm_lkb;
+struct dlm_rsb;
+struct dlm_member;
+struct dlm_lkbtable;
+struct dlm_rsbtable;
+struct dlm_dirtable;
+struct dlm_direntry;
+struct dlm_recover;
+struct dlm_header;
+struct dlm_message;
+struct dlm_rcom;
+struct dlm_mhandle;
+
+#define log_print(fmt, args...) \
+	printk(KERN_ERR "dlm: "fmt"\n" , ##args)
+#define log_error(ls, fmt, args...) \
+	printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args)
+
+#define DLM_LOG_DEBUG
+#ifdef DLM_LOG_DEBUG
+#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args)
+#else
+#define log_debug(ls, fmt, args...)
+#endif
+
+#define DLM_ASSERT(x, do) \
+{ \
+  if (!(x)) \
+  { \
+    printk(KERN_ERR "\nDLM:  Assertion failed on line %d of file %s\n" \
+               "DLM:  assertion:  \"%s\"\n" \
+               "DLM:  time = %lu\n", \
+               __LINE__, __FILE__, #x, jiffies); \
+    {do} \
+    printk("\n"); \
+    BUG(); \
+    panic("DLM:  Record message above and reboot.\n"); \
+  } \
+}
+
+#define DLM_FAKE_USER_AST ERR_PTR(-EINVAL)
+
+
+struct dlm_direntry {
+	struct list_head	list;
+	uint32_t		master_nodeid;
+	uint16_t		length;
+	char			name[1];
+};
+
+struct dlm_dirtable {
+	struct list_head	list;
+	rwlock_t		lock;
+};
+
+struct dlm_rsbtable {
+	struct list_head	list;
+	struct list_head	toss;
+	rwlock_t		lock;
+};
+
+struct dlm_lkbtable {
+	struct list_head	list;
+	rwlock_t		lock;
+	uint16_t		counter;
+};
+
+/*
+ * Lockspace member (per node in a ls)
+ */
+
+struct dlm_member {
+	struct list_head	list;
+	int			nodeid;
+	int			weight;
+};
+
+/*
+ * Save and manage recovery state for a lockspace.
+ */
+
+struct dlm_recover {
+	struct list_head	list;
+	int			*nodeids;
+	int			node_count;
+	uint64_t		seq;
+};
+
+/*
+ * Pass input args to second stage locking function.
+ */
+
+struct dlm_args {
+	uint32_t		flags;
+	void			*astaddr;
+	long			astparam;
+	void			*bastaddr;
+	int			mode;
+	struct dlm_lksb		*lksb;
+};
+
+
+/*
+ * Lock block
+ *
+ * A lock can be one of three types:
+ *
+ * local copy      lock is mastered locally
+ *                 (lkb_nodeid is zero and DLM_LKF_MSTCPY is not set)
+ * process copy    lock is mastered on a remote node
+ *                 (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is not set)
+ * master copy     master node's copy of a lock owned by remote node
+ *                 (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is set)
+ *
+ * lkb_exflags: a copy of the most recent flags arg provided to dlm_lock or
+ * dlm_unlock.  The dlm does not modify these or use any private flags in
+ * this field; it only contains DLM_LKF_ flags from dlm.h.  These flags
+ * are sent as-is to the remote master when the lock is remote.
+ *
+ * lkb_flags: internal dlm flags (DLM_IFL_ prefix) from dlm_internal.h.
+ * Some internal flags are shared between the master and process nodes;
+ * these shared flags are kept in the lower two bytes.  One of these
+ * flags set on the master copy will be propagated to the process copy
+ * and v.v.  Other internal flags are private to the master or process
+ * node (e.g. DLM_IFL_MSTCPY).  These are kept in the high two bytes.
+ *
+ * lkb_sbflags: status block flags.  These flags are copied directly into
+ * the caller's lksb.sb_flags prior to the dlm_lock/dlm_unlock completion
+ * ast.  All defined in dlm.h with DLM_SBF_ prefix.
+ *
+ * lkb_status: the lock status indicates which rsb queue the lock is
+ * on, grant, convert, or wait.  DLM_LKSTS_ WAITING/GRANTED/CONVERT
+ *
+ * lkb_wait_type: the dlm message type (DLM_MSG_ prefix) for which a
+ * reply is needed.  Only set when the lkb is on the lockspace waiters
+ * list awaiting a reply from a remote node.
+ *
+ * lkb_nodeid: when the lkb is a local copy, nodeid is 0; when the lkb
+ * is a master copy, nodeid specifies the remote lock holder, when the
+ * lkb is a process copy, the nodeid specifies the lock master.
+ */
+
+/* lkb_ast_type */
+
+#define AST_COMP		1
+#define AST_BAST		2
+
+/* lkb_status */
+
+#define DLM_LKSTS_WAITING	1
+#define DLM_LKSTS_GRANTED	2
+#define DLM_LKSTS_CONVERT	3
+
+/* lkb_flags */
+
+#define DLM_IFL_MSTCPY		0x00010000
+#define DLM_IFL_RESEND		0x00020000
+#define DLM_IFL_DEAD		0x00040000
+#define DLM_IFL_USER		0x00000001
+#define DLM_IFL_ORPHAN		0x00000002
+
+struct dlm_lkb {
+	struct dlm_rsb		*lkb_resource;	/* the rsb */
+	struct kref		lkb_ref;
+	int			lkb_nodeid;	/* copied from rsb */
+	int			lkb_ownpid;	/* pid of lock owner */
+	uint32_t		lkb_id;		/* our lock ID */
+	uint32_t		lkb_remid;	/* lock ID on remote partner */
+	uint32_t		lkb_exflags;	/* external flags from caller */
+	uint32_t		lkb_sbflags;	/* lksb flags */
+	uint32_t		lkb_flags;	/* internal flags */
+	uint32_t		lkb_lvbseq;	/* lvb sequence number */
+
+	int8_t			lkb_status;     /* granted, waiting, convert */
+	int8_t			lkb_rqmode;	/* requested lock mode */
+	int8_t			lkb_grmode;	/* granted lock mode */
+	int8_t			lkb_bastmode;	/* requested mode */
+	int8_t			lkb_highbast;	/* highest mode bast sent for */
+
+	int8_t			lkb_wait_type;	/* type of reply waiting for */
+	int8_t			lkb_ast_type;	/* type of ast queued for */
+
+	struct list_head	lkb_idtbl_list;	/* lockspace lkbtbl */
+	struct list_head	lkb_statequeue;	/* rsb g/c/w list */
+	struct list_head	lkb_rsb_lookup;	/* waiting for rsb lookup */
+	struct list_head	lkb_wait_reply;	/* waiting for remote reply */
+	struct list_head	lkb_astqueue;	/* need ast to be sent */
+	struct list_head	lkb_ownqueue;	/* list of locks for a process */
+
+	char			*lkb_lvbptr;
+	struct dlm_lksb		*lkb_lksb;      /* caller's status block */
+	void			*lkb_astaddr;	/* caller's ast function */
+	void			*lkb_bastaddr;	/* caller's bast function */
+	long			lkb_astparam;	/* caller's ast arg */
+};
+
+
+struct dlm_rsb {
+	struct dlm_ls		*res_ls;	/* the lockspace */
+	struct kref		res_ref;
+	struct mutex		res_mutex;
+	unsigned long		res_flags;
+	int			res_length;	/* length of rsb name */
+	int			res_nodeid;
+	uint32_t                res_lvbseq;
+	uint32_t		res_hash;
+	uint32_t		res_bucket;	/* rsbtbl */
+	unsigned long		res_toss_time;
+	uint32_t		res_first_lkid;
+	struct list_head	res_lookup;	/* lkbs waiting on first */
+	struct list_head	res_hashchain;	/* rsbtbl */
+	struct list_head	res_grantqueue;
+	struct list_head	res_convertqueue;
+	struct list_head	res_waitqueue;
+
+	struct list_head	res_root_list;	    /* used for recovery */
+	struct list_head	res_recover_list;   /* used for recovery */
+	int			res_recover_locks_count;
+
+	char			*res_lvbptr;
+	char			res_name[1];
+};
+
+/* find_rsb() flags */
+
+#define R_MASTER		1	/* only return rsb if it's a master */
+#define R_CREATE		2	/* create/add rsb if not found */
+
+/* rsb_flags */
+
+enum rsb_flags {
+	RSB_MASTER_UNCERTAIN,
+	RSB_VALNOTVALID,
+	RSB_VALNOTVALID_PREV,
+	RSB_NEW_MASTER,
+	RSB_NEW_MASTER2,
+	RSB_RECOVER_CONVERT,
+	RSB_LOCKS_PURGED,
+};
+
+static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+	__set_bit(flag, &r->res_flags);
+}
+
+static inline void rsb_clear_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+	__clear_bit(flag, &r->res_flags);
+}
+
+static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+	return test_bit(flag, &r->res_flags);
+}
+
+
+/* dlm_header is first element of all structs sent between nodes */
+
+#define DLM_HEADER_MAJOR	0x00020000
+#define DLM_HEADER_MINOR	0x00000001
+
+#define DLM_MSG			1
+#define DLM_RCOM		2
+
+struct dlm_header {
+	uint32_t		h_version;
+	uint32_t		h_lockspace;
+	uint32_t		h_nodeid;	/* nodeid of sender */
+	uint16_t		h_length;
+	uint8_t			h_cmd;		/* DLM_MSG, DLM_RCOM */
+	uint8_t			h_pad;
+};
+
+
+#define DLM_MSG_REQUEST		1
+#define DLM_MSG_CONVERT		2
+#define DLM_MSG_UNLOCK		3
+#define DLM_MSG_CANCEL		4
+#define DLM_MSG_REQUEST_REPLY	5
+#define DLM_MSG_CONVERT_REPLY	6
+#define DLM_MSG_UNLOCK_REPLY	7
+#define DLM_MSG_CANCEL_REPLY	8
+#define DLM_MSG_GRANT		9
+#define DLM_MSG_BAST		10
+#define DLM_MSG_LOOKUP		11
+#define DLM_MSG_REMOVE		12
+#define DLM_MSG_LOOKUP_REPLY	13
+
+struct dlm_message {
+	struct dlm_header	m_header;
+	uint32_t		m_type;		/* DLM_MSG_ */
+	uint32_t		m_nodeid;
+	uint32_t		m_pid;
+	uint32_t		m_lkid;		/* lkid on sender */
+	uint32_t		m_remid;	/* lkid on receiver */
+	uint32_t		m_parent_lkid;
+	uint32_t		m_parent_remid;
+	uint32_t		m_exflags;
+	uint32_t		m_sbflags;
+	uint32_t		m_flags;
+	uint32_t		m_lvbseq;
+	uint32_t		m_hash;
+	int			m_status;
+	int			m_grmode;
+	int			m_rqmode;
+	int			m_bastmode;
+	int			m_asts;
+	int			m_result;	/* 0 or -EXXX */
+	char			m_extra[0];	/* name or lvb */
+};
+
+
+#define DLM_RS_NODES		0x00000001
+#define DLM_RS_NODES_ALL	0x00000002
+#define DLM_RS_DIR		0x00000004
+#define DLM_RS_DIR_ALL		0x00000008
+#define DLM_RS_LOCKS		0x00000010
+#define DLM_RS_LOCKS_ALL	0x00000020
+#define DLM_RS_DONE		0x00000040
+#define DLM_RS_DONE_ALL		0x00000080
+
+#define DLM_RCOM_STATUS		1
+#define DLM_RCOM_NAMES		2
+#define DLM_RCOM_LOOKUP		3
+#define DLM_RCOM_LOCK		4
+#define DLM_RCOM_STATUS_REPLY	5
+#define DLM_RCOM_NAMES_REPLY	6
+#define DLM_RCOM_LOOKUP_REPLY	7
+#define DLM_RCOM_LOCK_REPLY	8
+
+struct dlm_rcom {
+	struct dlm_header	rc_header;
+	uint32_t		rc_type;	/* DLM_RCOM_ */
+	int			rc_result;	/* multi-purpose */
+	uint64_t		rc_id;		/* match reply with request */
+	char			rc_buf[0];
+};
+
+struct rcom_config {
+	uint32_t		rf_lvblen;
+	uint32_t		rf_lsflags;
+	uint64_t		rf_unused;
+};
+
+struct rcom_lock {
+	uint32_t		rl_ownpid;
+	uint32_t		rl_lkid;
+	uint32_t		rl_remid;
+	uint32_t		rl_parent_lkid;
+	uint32_t		rl_parent_remid;
+	uint32_t		rl_exflags;
+	uint32_t		rl_flags;
+	uint32_t		rl_lvbseq;
+	int			rl_result;
+	int8_t			rl_rqmode;
+	int8_t			rl_grmode;
+	int8_t			rl_status;
+	int8_t			rl_asts;
+	uint16_t		rl_wait_type;
+	uint16_t		rl_namelen;
+	char			rl_name[DLM_RESNAME_MAXLEN];
+	char			rl_lvb[0];
+};
+
+struct dlm_ls {
+	struct list_head	ls_list;	/* list of lockspaces */
+	dlm_lockspace_t		*ls_local_handle;
+	uint32_t		ls_global_id;	/* global unique lockspace ID */
+	uint32_t		ls_exflags;
+	int			ls_lvblen;
+	int			ls_count;	/* reference count */
+	unsigned long		ls_flags;	/* LSFL_ */
+	struct kobject		ls_kobj;
+
+	struct dlm_rsbtable	*ls_rsbtbl;
+	uint32_t		ls_rsbtbl_size;
+
+	struct dlm_lkbtable	*ls_lkbtbl;
+	uint32_t		ls_lkbtbl_size;
+
+	struct dlm_dirtable	*ls_dirtbl;
+	uint32_t		ls_dirtbl_size;
+
+	struct mutex		ls_waiters_mutex;
+	struct list_head	ls_waiters;	/* lkbs needing a reply */
+
+	struct list_head	ls_nodes;	/* current nodes in ls */
+	struct list_head	ls_nodes_gone;	/* dead node list, recovery */
+	int			ls_num_nodes;	/* number of nodes in ls */
+	int			ls_low_nodeid;
+	int			ls_total_weight;
+	int			*ls_node_array;
+
+	struct dlm_rsb		ls_stub_rsb;	/* for returning errors */
+	struct dlm_lkb		ls_stub_lkb;	/* for returning errors */
+	struct dlm_message	ls_stub_ms;	/* for faking a reply */
+
+	struct dentry		*ls_debug_rsb_dentry; /* debugfs */
+	struct dentry		*ls_debug_waiters_dentry; /* debugfs */
+
+	wait_queue_head_t	ls_uevent_wait;	/* user part of join/leave */
+	int			ls_uevent_result;
+
+	struct miscdevice       ls_device;
+
+	/* recovery related */
+
+	struct timer_list	ls_timer;
+	struct task_struct	*ls_recoverd_task;
+	struct mutex		ls_recoverd_active;
+	spinlock_t		ls_recover_lock;
+	uint32_t		ls_recover_status; /* DLM_RS_ */
+	uint64_t		ls_recover_seq;
+	struct dlm_recover	*ls_recover_args;
+	struct rw_semaphore	ls_in_recovery;	/* block local requests */
+	struct list_head	ls_requestqueue;/* queue remote requests */
+	struct mutex		ls_requestqueue_mutex;
+	char			*ls_recover_buf;
+	int			ls_recover_nodeid; /* for debugging */
+	uint64_t		ls_rcom_seq;
+	struct list_head	ls_recover_list;
+	spinlock_t		ls_recover_list_lock;
+	int			ls_recover_list_count;
+	wait_queue_head_t	ls_wait_general;
+	struct mutex		ls_clear_proc_locks;
+
+	struct list_head	ls_root_list;	/* root resources */
+	struct rw_semaphore	ls_root_sem;	/* protect root_list */
+
+	int			ls_namelen;
+	char			ls_name[1];
+};
+
+#define LSFL_WORK		0
+#define LSFL_RUNNING		1
+#define LSFL_RECOVERY_STOP	2
+#define LSFL_RCOM_READY		3
+#define LSFL_UEVENT_WAIT	4
+
+/* much of this is just saving user space pointers associated with the
+   lock that we pass back to the user lib with an ast */
+
+struct dlm_user_args {
+	struct dlm_user_proc	*proc; /* each process that opens the lockspace
+					  device has private data
+					  (dlm_user_proc) on the struct file,
+					  the process's locks point back to it*/
+	struct dlm_lksb		lksb;
+	int			old_mode;
+	int			update_user_lvb;
+	struct dlm_lksb __user	*user_lksb;
+	void __user		*castparam;
+	void __user		*castaddr;
+	void __user		*bastparam;
+	void __user		*bastaddr;
+};
+
+#define DLM_PROC_FLAGS_CLOSING 1
+#define DLM_PROC_FLAGS_COMPAT  2
+
+/* locks list is kept so we can remove all a process's locks when it
+   exits (or orphan those that are persistent) */
+
+struct dlm_user_proc {
+	dlm_lockspace_t		*lockspace;
+	unsigned long		flags; /* DLM_PROC_FLAGS */
+	struct list_head	asts;
+	spinlock_t		asts_spin;
+	struct list_head	locks;
+	spinlock_t		locks_spin;
+	wait_queue_head_t	wait;
+};
+
+static inline int dlm_locking_stopped(struct dlm_ls *ls)
+{
+	return !test_bit(LSFL_RUNNING, &ls->ls_flags);
+}
+
+static inline int dlm_recovery_stopped(struct dlm_ls *ls)
+{
+	return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+}
+
+static inline int dlm_no_directory(struct dlm_ls *ls)
+{
+	return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0;
+}
+
+#endif				/* __DLM_INTERNAL_DOT_H__ */
+
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
new file mode 100644
index 0000000..3f2befa
--- /dev/null
+++ b/fs/dlm/lock.c
@@ -0,0 +1,3871 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/* Central locking logic has four stages:
+
+   dlm_lock()
+   dlm_unlock()
+
+   request_lock(ls, lkb)
+   convert_lock(ls, lkb)
+   unlock_lock(ls, lkb)
+   cancel_lock(ls, lkb)
+
+   _request_lock(r, lkb)
+   _convert_lock(r, lkb)
+   _unlock_lock(r, lkb)
+   _cancel_lock(r, lkb)
+
+   do_request(r, lkb)
+   do_convert(r, lkb)
+   do_unlock(r, lkb)
+   do_cancel(r, lkb)
+
+   Stage 1 (lock, unlock) is mainly about checking input args and
+   splitting into one of the four main operations:
+
+       dlm_lock          = request_lock
+       dlm_lock+CONVERT  = convert_lock
+       dlm_unlock        = unlock_lock
+       dlm_unlock+CANCEL = cancel_lock
+
+   Stage 2, xxxx_lock(), just finds and locks the relevant rsb which is
+   provided to the next stage.
+
+   Stage 3, _xxxx_lock(), determines if the operation is local or remote.
+   When remote, it calls send_xxxx(), when local it calls do_xxxx().
+
+   Stage 4, do_xxxx(), is the guts of the operation.  It manipulates the
+   given rsb and lkb and queues callbacks.
+
+   For remote operations, send_xxxx() results in the corresponding do_xxxx()
+   function being executed on the remote node.  The connecting send/receive
+   calls on local (L) and remote (R) nodes:
+
+   L: send_xxxx()              ->  R: receive_xxxx()
+                                   R: do_xxxx()
+   L: receive_xxxx_reply()     <-  R: send_xxxx_reply()
+*/
+#include <linux/types.h>
+#include "dlm_internal.h"
+#include <linux/dlm_device.h>
+#include "memory.h"
+#include "lowcomms.h"
+#include "requestqueue.h"
+#include "util.h"
+#include "dir.h"
+#include "member.h"
+#include "lockspace.h"
+#include "ast.h"
+#include "lock.h"
+#include "rcom.h"
+#include "recover.h"
+#include "lvb_table.h"
+#include "user.h"
+#include "config.h"
+
+static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode);
+static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_remove(struct dlm_rsb *r);
+static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+				    struct dlm_message *ms);
+static int receive_extralen(struct dlm_message *ms);
+
+/*
+ * Lock compatibilty matrix - thanks Steve
+ * UN = Unlocked state. Not really a state, used as a flag
+ * PD = Padding. Used to make the matrix a nice power of two in size
+ * Other states are the same as the VMS DLM.
+ * Usage: matrix[grmode+1][rqmode+1]  (although m[rq+1][gr+1] is the same)
+ */
+
+static const int __dlm_compat_matrix[8][8] = {
+      /* UN NL CR CW PR PW EX PD */
+        {1, 1, 1, 1, 1, 1, 1, 0},       /* UN */
+        {1, 1, 1, 1, 1, 1, 1, 0},       /* NL */
+        {1, 1, 1, 1, 1, 1, 0, 0},       /* CR */
+        {1, 1, 1, 1, 0, 0, 0, 0},       /* CW */
+        {1, 1, 1, 0, 1, 0, 0, 0},       /* PR */
+        {1, 1, 1, 0, 0, 0, 0, 0},       /* PW */
+        {1, 1, 0, 0, 0, 0, 0, 0},       /* EX */
+        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */
+};
+
+/*
+ * This defines the direction of transfer of LVB data.
+ * Granted mode is the row; requested mode is the column.
+ * Usage: matrix[grmode+1][rqmode+1]
+ * 1 = LVB is returned to the caller
+ * 0 = LVB is written to the resource
+ * -1 = nothing happens to the LVB
+ */
+
+const int dlm_lvb_operations[8][8] = {
+        /* UN   NL  CR  CW  PR  PW  EX  PD*/
+        {  -1,  1,  1,  1,  1,  1,  1, -1 }, /* UN */
+        {  -1,  1,  1,  1,  1,  1,  1,  0 }, /* NL */
+        {  -1, -1,  1,  1,  1,  1,  1,  0 }, /* CR */
+        {  -1, -1, -1,  1,  1,  1,  1,  0 }, /* CW */
+        {  -1, -1, -1, -1,  1,  1,  1,  0 }, /* PR */
+        {  -1,  0,  0,  0,  0,  0,  1,  0 }, /* PW */
+        {  -1,  0,  0,  0,  0,  0,  0,  0 }, /* EX */
+        {  -1,  0,  0,  0,  0,  0,  0,  0 }  /* PD */
+};
+
+#define modes_compat(gr, rq) \
+	__dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1]
+
+int dlm_modes_compat(int mode1, int mode2)
+{
+	return __dlm_compat_matrix[mode1 + 1][mode2 + 1];
+}
+
+/*
+ * Compatibility matrix for conversions with QUECVT set.
+ * Granted mode is the row; requested mode is the column.
+ * Usage: matrix[grmode+1][rqmode+1]
+ */
+
+static const int __quecvt_compat_matrix[8][8] = {
+      /* UN NL CR CW PR PW EX PD */
+        {0, 0, 0, 0, 0, 0, 0, 0},       /* UN */
+        {0, 0, 1, 1, 1, 1, 1, 0},       /* NL */
+        {0, 0, 0, 1, 1, 1, 1, 0},       /* CR */
+        {0, 0, 0, 0, 1, 1, 1, 0},       /* CW */
+        {0, 0, 0, 1, 0, 1, 1, 0},       /* PR */
+        {0, 0, 0, 0, 0, 0, 1, 0},       /* PW */
+        {0, 0, 0, 0, 0, 0, 0, 0},       /* EX */
+        {0, 0, 0, 0, 0, 0, 0, 0}        /* PD */
+};
+
+void dlm_print_lkb(struct dlm_lkb *lkb)
+{
+	printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n"
+	       "     status %d rqmode %d grmode %d wait_type %d ast_type %d\n",
+	       lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
+	       lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,
+	       lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
+}
+
+void dlm_print_rsb(struct dlm_rsb *r)
+{
+	printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
+	       r->res_nodeid, r->res_flags, r->res_first_lkid,
+	       r->res_recover_locks_count, r->res_name);
+}
+
+void dlm_dump_rsb(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb;
+
+	dlm_print_rsb(r);
+
+	printk(KERN_ERR "rsb: root_list empty %d recover_list empty %d\n",
+	       list_empty(&r->res_root_list), list_empty(&r->res_recover_list));
+	printk(KERN_ERR "rsb lookup list\n");
+	list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup)
+		dlm_print_lkb(lkb);
+	printk(KERN_ERR "rsb grant queue:\n");
+	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue)
+		dlm_print_lkb(lkb);
+	printk(KERN_ERR "rsb convert queue:\n");
+	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue)
+		dlm_print_lkb(lkb);
+	printk(KERN_ERR "rsb wait queue:\n");
+	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue)
+		dlm_print_lkb(lkb);
+}
+
+/* Threads cannot use the lockspace while it's being recovered */
+
+static inline void lock_recovery(struct dlm_ls *ls)
+{
+	down_read(&ls->ls_in_recovery);
+}
+
+static inline void unlock_recovery(struct dlm_ls *ls)
+{
+	up_read(&ls->ls_in_recovery);
+}
+
+static inline int lock_recovery_try(struct dlm_ls *ls)
+{
+	return down_read_trylock(&ls->ls_in_recovery);
+}
+
+static inline int can_be_queued(struct dlm_lkb *lkb)
+{
+	return !(lkb->lkb_exflags & DLM_LKF_NOQUEUE);
+}
+
+static inline int force_blocking_asts(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_exflags & DLM_LKF_NOQUEUEBAST);
+}
+
+static inline int is_demoted(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_sbflags & DLM_SBF_DEMOTED);
+}
+
+static inline int is_remote(struct dlm_rsb *r)
+{
+	DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
+	return !!r->res_nodeid;
+}
+
+static inline int is_process_copy(struct dlm_lkb *lkb)
+{
+	return (lkb->lkb_nodeid && !(lkb->lkb_flags & DLM_IFL_MSTCPY));
+}
+
+static inline int is_master_copy(struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+		DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb););
+	return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0;
+}
+
+static inline int middle_conversion(struct dlm_lkb *lkb)
+{
+	if ((lkb->lkb_grmode==DLM_LOCK_PR && lkb->lkb_rqmode==DLM_LOCK_CW) ||
+	    (lkb->lkb_rqmode==DLM_LOCK_PR && lkb->lkb_grmode==DLM_LOCK_CW))
+		return 1;
+	return 0;
+}
+
+static inline int down_conversion(struct dlm_lkb *lkb)
+{
+	return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode);
+}
+
+static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	if (is_master_copy(lkb))
+		return;
+
+	DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
+
+	lkb->lkb_lksb->sb_status = rv;
+	lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
+
+	dlm_add_ast(lkb, AST_COMP);
+}
+
+static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
+{
+	if (is_master_copy(lkb))
+		send_bast(r, lkb, rqmode);
+	else {
+		lkb->lkb_bastmode = rqmode;
+		dlm_add_ast(lkb, AST_BAST);
+	}
+}
+
+/*
+ * Basic operations on rsb's and lkb's
+ */
+
+static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len)
+{
+	struct dlm_rsb *r;
+
+	r = allocate_rsb(ls, len);
+	if (!r)
+		return NULL;
+
+	r->res_ls = ls;
+	r->res_length = len;
+	memcpy(r->res_name, name, len);
+	mutex_init(&r->res_mutex);
+
+	INIT_LIST_HEAD(&r->res_lookup);
+	INIT_LIST_HEAD(&r->res_grantqueue);
+	INIT_LIST_HEAD(&r->res_convertqueue);
+	INIT_LIST_HEAD(&r->res_waitqueue);
+	INIT_LIST_HEAD(&r->res_root_list);
+	INIT_LIST_HEAD(&r->res_recover_list);
+
+	return r;
+}
+
+static int search_rsb_list(struct list_head *head, char *name, int len,
+			   unsigned int flags, struct dlm_rsb **r_ret)
+{
+	struct dlm_rsb *r;
+	int error = 0;
+
+	list_for_each_entry(r, head, res_hashchain) {
+		if (len == r->res_length && !memcmp(name, r->res_name, len))
+			goto found;
+	}
+	return -EBADR;
+
+ found:
+	if (r->res_nodeid && (flags & R_MASTER))
+		error = -ENOTBLK;
+	*r_ret = r;
+	return error;
+}
+
+static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
+		       unsigned int flags, struct dlm_rsb **r_ret)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	error = search_rsb_list(&ls->ls_rsbtbl[b].list, name, len, flags, &r);
+	if (!error) {
+		kref_get(&r->res_ref);
+		goto out;
+	}
+	error = search_rsb_list(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
+	if (error)
+		goto out;
+
+	list_move(&r->res_hashchain, &ls->ls_rsbtbl[b].list);
+
+	if (dlm_no_directory(ls))
+		goto out;
+
+	if (r->res_nodeid == -1) {
+		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
+		r->res_first_lkid = 0;
+	} else if (r->res_nodeid > 0) {
+		rsb_set_flag(r, RSB_MASTER_UNCERTAIN);
+		r->res_first_lkid = 0;
+	} else {
+		DLM_ASSERT(r->res_nodeid == 0, dlm_print_rsb(r););
+		DLM_ASSERT(!rsb_flag(r, RSB_MASTER_UNCERTAIN),);
+	}
+ out:
+	*r_ret = r;
+	return error;
+}
+
+static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
+		      unsigned int flags, struct dlm_rsb **r_ret)
+{
+	int error;
+	write_lock(&ls->ls_rsbtbl[b].lock);
+	error = _search_rsb(ls, name, len, b, flags, r_ret);
+	write_unlock(&ls->ls_rsbtbl[b].lock);
+	return error;
+}
+
+/*
+ * Find rsb in rsbtbl and potentially create/add one
+ *
+ * Delaying the release of rsb's has a similar benefit to applications keeping
+ * NL locks on an rsb, but without the guarantee that the cached master value
+ * will still be valid when the rsb is reused.  Apps aren't always smart enough
+ * to keep NL locks on an rsb that they may lock again shortly; this can lead
+ * to excessive master lookups and removals if we don't delay the release.
+ *
+ * Searching for an rsb means looking through both the normal list and toss
+ * list.  When found on the toss list the rsb is moved to the normal list with
+ * ref count of 1; when found on normal list the ref count is incremented.
+ */
+
+static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
+		    unsigned int flags, struct dlm_rsb **r_ret)
+{
+	struct dlm_rsb *r, *tmp;
+	uint32_t hash, bucket;
+	int error = 0;
+
+	if (dlm_no_directory(ls))
+		flags |= R_CREATE;
+
+	hash = jhash(name, namelen, 0);
+	bucket = hash & (ls->ls_rsbtbl_size - 1);
+
+	error = search_rsb(ls, name, namelen, bucket, flags, &r);
+	if (!error)
+		goto out;
+
+	if (error == -EBADR && !(flags & R_CREATE))
+		goto out;
+
+	/* the rsb was found but wasn't a master copy */
+	if (error == -ENOTBLK)
+		goto out;
+
+	error = -ENOMEM;
+	r = create_rsb(ls, name, namelen);
+	if (!r)
+		goto out;
+
+	r->res_hash = hash;
+	r->res_bucket = bucket;
+	r->res_nodeid = -1;
+	kref_init(&r->res_ref);
+
+	/* With no directory, the master can be set immediately */
+	if (dlm_no_directory(ls)) {
+		int nodeid = dlm_dir_nodeid(r);
+		if (nodeid == dlm_our_nodeid())
+			nodeid = 0;
+		r->res_nodeid = nodeid;
+	}
+
+	write_lock(&ls->ls_rsbtbl[bucket].lock);
+	error = _search_rsb(ls, name, namelen, bucket, 0, &tmp);
+	if (!error) {
+		write_unlock(&ls->ls_rsbtbl[bucket].lock);
+		free_rsb(r);
+		r = tmp;
+		goto out;
+	}
+	list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list);
+	write_unlock(&ls->ls_rsbtbl[bucket].lock);
+	error = 0;
+ out:
+	*r_ret = r;
+	return error;
+}
+
+int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
+		 unsigned int flags, struct dlm_rsb **r_ret)
+{
+	return find_rsb(ls, name, namelen, flags, r_ret);
+}
+
+/* This is only called to add a reference when the code already holds
+   a valid reference to the rsb, so there's no need for locking. */
+
+static inline void hold_rsb(struct dlm_rsb *r)
+{
+	kref_get(&r->res_ref);
+}
+
+void dlm_hold_rsb(struct dlm_rsb *r)
+{
+	hold_rsb(r);
+}
+
+static void toss_rsb(struct kref *kref)
+{
+	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
+	struct dlm_ls *ls = r->res_ls;
+
+	DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r););
+	kref_init(&r->res_ref);
+	list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss);
+	r->res_toss_time = jiffies;
+	if (r->res_lvbptr) {
+		free_lvb(r->res_lvbptr);
+		r->res_lvbptr = NULL;
+	}
+}
+
+/* When all references to the rsb are gone it's transfered to
+   the tossed list for later disposal. */
+
+static void put_rsb(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+	uint32_t bucket = r->res_bucket;
+
+	write_lock(&ls->ls_rsbtbl[bucket].lock);
+	kref_put(&r->res_ref, toss_rsb);
+	write_unlock(&ls->ls_rsbtbl[bucket].lock);
+}
+
+void dlm_put_rsb(struct dlm_rsb *r)
+{
+	put_rsb(r);
+}
+
+/* See comment for unhold_lkb */
+
+static void unhold_rsb(struct dlm_rsb *r)
+{
+	int rv;
+	rv = kref_put(&r->res_ref, toss_rsb);
+	DLM_ASSERT(!rv, dlm_dump_rsb(r););
+}
+
+static void kill_rsb(struct kref *kref)
+{
+	struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
+
+	/* All work is done after the return from kref_put() so we
+	   can release the write_lock before the remove and free. */
+
+	DLM_ASSERT(list_empty(&r->res_lookup), dlm_dump_rsb(r););
+	DLM_ASSERT(list_empty(&r->res_grantqueue), dlm_dump_rsb(r););
+	DLM_ASSERT(list_empty(&r->res_convertqueue), dlm_dump_rsb(r););
+	DLM_ASSERT(list_empty(&r->res_waitqueue), dlm_dump_rsb(r););
+	DLM_ASSERT(list_empty(&r->res_root_list), dlm_dump_rsb(r););
+	DLM_ASSERT(list_empty(&r->res_recover_list), dlm_dump_rsb(r););
+}
+
+/* Attaching/detaching lkb's from rsb's is for rsb reference counting.
+   The rsb must exist as long as any lkb's for it do. */
+
+static void attach_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	hold_rsb(r);
+	lkb->lkb_resource = r;
+}
+
+static void detach_lkb(struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_resource) {
+		put_rsb(lkb->lkb_resource);
+		lkb->lkb_resource = NULL;
+	}
+}
+
+static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+{
+	struct dlm_lkb *lkb, *tmp;
+	uint32_t lkid = 0;
+	uint16_t bucket;
+
+	lkb = allocate_lkb(ls);
+	if (!lkb)
+		return -ENOMEM;
+
+	lkb->lkb_nodeid = -1;
+	lkb->lkb_grmode = DLM_LOCK_IV;
+	kref_init(&lkb->lkb_ref);
+	INIT_LIST_HEAD(&lkb->lkb_ownqueue);
+
+	get_random_bytes(&bucket, sizeof(bucket));
+	bucket &= (ls->ls_lkbtbl_size - 1);
+
+	write_lock(&ls->ls_lkbtbl[bucket].lock);
+
+	/* counter can roll over so we must verify lkid is not in use */
+
+	while (lkid == 0) {
+		lkid = bucket | (ls->ls_lkbtbl[bucket].counter++ << 16);
+
+		list_for_each_entry(tmp, &ls->ls_lkbtbl[bucket].list,
+				    lkb_idtbl_list) {
+			if (tmp->lkb_id != lkid)
+				continue;
+			lkid = 0;
+			break;
+		}
+	}
+
+	lkb->lkb_id = lkid;
+	list_add(&lkb->lkb_idtbl_list, &ls->ls_lkbtbl[bucket].list);
+	write_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+	*lkb_ret = lkb;
+	return 0;
+}
+
+static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)
+{
+	uint16_t bucket = lkid & 0xFFFF;
+	struct dlm_lkb *lkb;
+
+	list_for_each_entry(lkb, &ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) {
+		if (lkb->lkb_id == lkid)
+			return lkb;
+	}
+	return NULL;
+}
+
+static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)
+{
+	struct dlm_lkb *lkb;
+	uint16_t bucket = lkid & 0xFFFF;
+
+	if (bucket >= ls->ls_lkbtbl_size)
+		return -EBADSLT;
+
+	read_lock(&ls->ls_lkbtbl[bucket].lock);
+	lkb = __find_lkb(ls, lkid);
+	if (lkb)
+		kref_get(&lkb->lkb_ref);
+	read_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+	*lkb_ret = lkb;
+	return lkb ? 0 : -ENOENT;
+}
+
+static void kill_lkb(struct kref *kref)
+{
+	struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);
+
+	/* All work is done after the return from kref_put() so we
+	   can release the write_lock before the detach_lkb */
+
+	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
+}
+
+/* __put_lkb() is used when an lkb may not have an rsb attached to
+   it so we need to provide the lockspace explicitly */
+
+static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	uint16_t bucket = lkb->lkb_id & 0xFFFF;
+
+	write_lock(&ls->ls_lkbtbl[bucket].lock);
+	if (kref_put(&lkb->lkb_ref, kill_lkb)) {
+		list_del(&lkb->lkb_idtbl_list);
+		write_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+		detach_lkb(lkb);
+
+		/* for local/process lkbs, lvbptr points to caller's lksb */
+		if (lkb->lkb_lvbptr && is_master_copy(lkb))
+			free_lvb(lkb->lkb_lvbptr);
+		free_lkb(lkb);
+		return 1;
+	} else {
+		write_unlock(&ls->ls_lkbtbl[bucket].lock);
+		return 0;
+	}
+}
+
+int dlm_put_lkb(struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls;
+
+	DLM_ASSERT(lkb->lkb_resource, dlm_print_lkb(lkb););
+	DLM_ASSERT(lkb->lkb_resource->res_ls, dlm_print_lkb(lkb););
+
+	ls = lkb->lkb_resource->res_ls;
+	return __put_lkb(ls, lkb);
+}
+
+/* This is only called to add a reference when the code already holds
+   a valid reference to the lkb, so there's no need for locking. */
+
+static inline void hold_lkb(struct dlm_lkb *lkb)
+{
+	kref_get(&lkb->lkb_ref);
+}
+
+/* This is called when we need to remove a reference and are certain
+   it's not the last ref.  e.g. del_lkb is always called between a
+   find_lkb/put_lkb and is always the inverse of a previous add_lkb.
+   put_lkb would work fine, but would involve unnecessary locking */
+
+static inline void unhold_lkb(struct dlm_lkb *lkb)
+{
+	int rv;
+	rv = kref_put(&lkb->lkb_ref, kill_lkb);
+	DLM_ASSERT(!rv, dlm_print_lkb(lkb););
+}
+
+static void lkb_add_ordered(struct list_head *new, struct list_head *head,
+			    int mode)
+{
+	struct dlm_lkb *lkb = NULL;
+
+	list_for_each_entry(lkb, head, lkb_statequeue)
+		if (lkb->lkb_rqmode < mode)
+			break;
+
+	if (!lkb)
+		list_add_tail(new, head);
+	else
+		__list_add(new, lkb->lkb_statequeue.prev, &lkb->lkb_statequeue);
+}
+
+/* add/remove lkb to rsb's grant/convert/wait queue */
+
+static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
+{
+	kref_get(&lkb->lkb_ref);
+
+	DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
+
+	lkb->lkb_status = status;
+
+	switch (status) {
+	case DLM_LKSTS_WAITING:
+		if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
+			list_add(&lkb->lkb_statequeue, &r->res_waitqueue);
+		else
+			list_add_tail(&lkb->lkb_statequeue, &r->res_waitqueue);
+		break;
+	case DLM_LKSTS_GRANTED:
+		/* convention says granted locks kept in order of grmode */
+		lkb_add_ordered(&lkb->lkb_statequeue, &r->res_grantqueue,
+				lkb->lkb_grmode);
+		break;
+	case DLM_LKSTS_CONVERT:
+		if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
+			list_add(&lkb->lkb_statequeue, &r->res_convertqueue);
+		else
+			list_add_tail(&lkb->lkb_statequeue,
+				      &r->res_convertqueue);
+		break;
+	default:
+		DLM_ASSERT(0, dlm_print_lkb(lkb); printk("sts=%d\n", status););
+	}
+}
+
+static void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	lkb->lkb_status = 0;
+	list_del(&lkb->lkb_statequeue);
+	unhold_lkb(lkb);
+}
+
+static void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts)
+{
+	hold_lkb(lkb);
+	del_lkb(r, lkb);
+	add_lkb(r, lkb, sts);
+	unhold_lkb(lkb);
+}
+
+/* add/remove lkb from global waiters list of lkb's waiting for
+   a reply from a remote node */
+
+static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
+{
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+	if (lkb->lkb_wait_type) {
+		log_print("add_to_waiters error %d", lkb->lkb_wait_type);
+		goto out;
+	}
+	lkb->lkb_wait_type = mstype;
+	kref_get(&lkb->lkb_ref);
+	list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
+ out:
+	mutex_unlock(&ls->ls_waiters_mutex);
+}
+
+static int _remove_from_waiters(struct dlm_lkb *lkb)
+{
+	int error = 0;
+
+	if (!lkb->lkb_wait_type) {
+		log_print("remove_from_waiters error");
+		error = -EINVAL;
+		goto out;
+	}
+	lkb->lkb_wait_type = 0;
+	list_del(&lkb->lkb_wait_reply);
+	unhold_lkb(lkb);
+ out:
+	return error;
+}
+
+static int remove_from_waiters(struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+	int error;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+	error = _remove_from_waiters(lkb);
+	mutex_unlock(&ls->ls_waiters_mutex);
+	return error;
+}
+
+static void dir_remove(struct dlm_rsb *r)
+{
+	int to_nodeid;
+
+	if (dlm_no_directory(r->res_ls))
+		return;
+
+	to_nodeid = dlm_dir_nodeid(r);
+	if (to_nodeid != dlm_our_nodeid())
+		send_remove(r);
+	else
+		dlm_dir_remove_entry(r->res_ls, to_nodeid,
+				     r->res_name, r->res_length);
+}
+
+/* FIXME: shouldn't this be able to exit as soon as one non-due rsb is
+   found since they are in order of newest to oldest? */
+
+static int shrink_bucket(struct dlm_ls *ls, int b)
+{
+	struct dlm_rsb *r;
+	int count = 0, found;
+
+	for (;;) {
+		found = 0;
+		write_lock(&ls->ls_rsbtbl[b].lock);
+		list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
+					    res_hashchain) {
+			if (!time_after_eq(jiffies, r->res_toss_time +
+					   dlm_config.toss_secs * HZ))
+				continue;
+			found = 1;
+			break;
+		}
+
+		if (!found) {
+			write_unlock(&ls->ls_rsbtbl[b].lock);
+			break;
+		}
+
+		if (kref_put(&r->res_ref, kill_rsb)) {
+			list_del(&r->res_hashchain);
+			write_unlock(&ls->ls_rsbtbl[b].lock);
+
+			if (is_master(r))
+				dir_remove(r);
+			free_rsb(r);
+			count++;
+		} else {
+			write_unlock(&ls->ls_rsbtbl[b].lock);
+			log_error(ls, "tossed rsb in use %s", r->res_name);
+		}
+	}
+
+	return count;
+}
+
+void dlm_scan_rsbs(struct dlm_ls *ls)
+{
+	int i;
+
+	if (dlm_locking_stopped(ls))
+		return;
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		shrink_bucket(ls, i);
+		cond_resched();
+	}
+}
+
+/* lkb is master or local copy */
+
+static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int b, len = r->res_ls->ls_lvblen;
+
+	/* b=1 lvb returned to caller
+	   b=0 lvb written to rsb or invalidated
+	   b=-1 do nothing */
+
+	b =  dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
+
+	if (b == 1) {
+		if (!lkb->lkb_lvbptr)
+			return;
+
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			return;
+
+		if (!r->res_lvbptr)
+			return;
+
+		memcpy(lkb->lkb_lvbptr, r->res_lvbptr, len);
+		lkb->lkb_lvbseq = r->res_lvbseq;
+
+	} else if (b == 0) {
+		if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
+			rsb_set_flag(r, RSB_VALNOTVALID);
+			return;
+		}
+
+		if (!lkb->lkb_lvbptr)
+			return;
+
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			return;
+
+		if (!r->res_lvbptr)
+			r->res_lvbptr = allocate_lvb(r->res_ls);
+
+		if (!r->res_lvbptr)
+			return;
+
+		memcpy(r->res_lvbptr, lkb->lkb_lvbptr, len);
+		r->res_lvbseq++;
+		lkb->lkb_lvbseq = r->res_lvbseq;
+		rsb_clear_flag(r, RSB_VALNOTVALID);
+	}
+
+	if (rsb_flag(r, RSB_VALNOTVALID))
+		lkb->lkb_sbflags |= DLM_SBF_VALNOTVALID;
+}
+
+static void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_grmode < DLM_LOCK_PW)
+		return;
+
+	if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
+		rsb_set_flag(r, RSB_VALNOTVALID);
+		return;
+	}
+
+	if (!lkb->lkb_lvbptr)
+		return;
+
+	if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+		return;
+
+	if (!r->res_lvbptr)
+		r->res_lvbptr = allocate_lvb(r->res_ls);
+
+	if (!r->res_lvbptr)
+		return;
+
+	memcpy(r->res_lvbptr, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+	r->res_lvbseq++;
+	rsb_clear_flag(r, RSB_VALNOTVALID);
+}
+
+/* lkb is process copy (pc) */
+
+static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			    struct dlm_message *ms)
+{
+	int b;
+
+	if (!lkb->lkb_lvbptr)
+		return;
+
+	if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+		return;
+
+	b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
+	if (b == 1) {
+		int len = receive_extralen(ms);
+		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
+		lkb->lkb_lvbseq = ms->m_lvbseq;
+	}
+}
+
+/* Manipulate lkb's on rsb's convert/granted/waiting queues
+   remove_lock -- used for unlock, removes lkb from granted
+   revert_lock -- used for cancel, moves lkb from convert to granted
+   grant_lock  -- used for request and convert, adds lkb to granted or
+                  moves lkb from convert or waiting to granted
+
+   Each of these is used for master or local copy lkb's.  There is
+   also a _pc() variation used to make the corresponding change on
+   a process copy (pc) lkb. */
+
+static void _remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	del_lkb(r, lkb);
+	lkb->lkb_grmode = DLM_LOCK_IV;
+	/* this unhold undoes the original ref from create_lkb()
+	   so this leads to the lkb being freed */
+	unhold_lkb(lkb);
+}
+
+static void remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	set_lvb_unlock(r, lkb);
+	_remove_lock(r, lkb);
+}
+
+static void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	_remove_lock(r, lkb);
+}
+
+static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	lkb->lkb_rqmode = DLM_LOCK_IV;
+
+	switch (lkb->lkb_status) {
+	case DLM_LKSTS_GRANTED:
+		break;
+	case DLM_LKSTS_CONVERT:
+		move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+		break;
+	case DLM_LKSTS_WAITING:
+		del_lkb(r, lkb);
+		lkb->lkb_grmode = DLM_LOCK_IV;
+		/* this unhold undoes the original ref from create_lkb()
+		   so this leads to the lkb being freed */
+		unhold_lkb(lkb);
+		break;
+	default:
+		log_print("invalid status for revert %d", lkb->lkb_status);
+	}
+}
+
+static void revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	revert_lock(r, lkb);
+}
+
+static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_grmode != lkb->lkb_rqmode) {
+		lkb->lkb_grmode = lkb->lkb_rqmode;
+		if (lkb->lkb_status)
+			move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+		else
+			add_lkb(r, lkb, DLM_LKSTS_GRANTED);
+	}
+
+	lkb->lkb_rqmode = DLM_LOCK_IV;
+}
+
+static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	set_lvb_lock(r, lkb);
+	_grant_lock(r, lkb);
+	lkb->lkb_highbast = 0;
+}
+
+static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			  struct dlm_message *ms)
+{
+	set_lvb_lock_pc(r, lkb, ms);
+	_grant_lock(r, lkb);
+}
+
+/* called by grant_pending_locks() which means an async grant message must
+   be sent to the requesting node in addition to granting the lock if the
+   lkb belongs to a remote node. */
+
+static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	grant_lock(r, lkb);
+	if (is_master_copy(lkb))
+		send_grant(r, lkb);
+	else
+		queue_cast(r, lkb, 0);
+}
+
+static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
+{
+	struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
+					   lkb_statequeue);
+	if (lkb->lkb_id == first->lkb_id)
+		return 1;
+
+	return 0;
+}
+
+/* Check if the given lkb conflicts with another lkb on the queue. */
+
+static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb)
+{
+	struct dlm_lkb *this;
+
+	list_for_each_entry(this, head, lkb_statequeue) {
+		if (this == lkb)
+			continue;
+		if (!modes_compat(this, lkb))
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * "A conversion deadlock arises with a pair of lock requests in the converting
+ * queue for one resource.  The granted mode of each lock blocks the requested
+ * mode of the other lock."
+ *
+ * Part 2: if the granted mode of lkb is preventing the first lkb in the
+ * convert queue from being granted, then demote lkb (set grmode to NL).
+ * This second form requires that we check for conv-deadlk even when
+ * now == 0 in _can_be_granted().
+ *
+ * Example:
+ * Granted Queue: empty
+ * Convert Queue: NL->EX (first lock)
+ *                PR->EX (second lock)
+ *
+ * The first lock can't be granted because of the granted mode of the second
+ * lock and the second lock can't be granted because it's not first in the
+ * list.  We demote the granted mode of the second lock (the lkb passed to this
+ * function).
+ *
+ * After the resolution, the "grant pending" function needs to go back and try
+ * to grant locks on the convert queue again since the first lock can now be
+ * granted.
+ */
+
+static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb)
+{
+	struct dlm_lkb *this, *first = NULL, *self = NULL;
+
+	list_for_each_entry(this, &rsb->res_convertqueue, lkb_statequeue) {
+		if (!first)
+			first = this;
+		if (this == lkb) {
+			self = lkb;
+			continue;
+		}
+
+		if (!modes_compat(this, lkb) && !modes_compat(lkb, this))
+			return 1;
+	}
+
+	/* if lkb is on the convert queue and is preventing the first
+	   from being granted, then there's deadlock and we demote lkb.
+	   multiple converting locks may need to do this before the first
+	   converting lock can be granted. */
+
+	if (self && self != first) {
+		if (!modes_compat(lkb, first) &&
+		    !queue_conflict(&rsb->res_grantqueue, first))
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * Return 1 if the lock can be granted, 0 otherwise.
+ * Also detect and resolve conversion deadlocks.
+ *
+ * lkb is the lock to be granted
+ *
+ * now is 1 if the function is being called in the context of the
+ * immediate request, it is 0 if called later, after the lock has been
+ * queued.
+ *
+ * References are from chapter 6 of "VAXcluster Principles" by Roy Davis
+ */
+
+static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
+{
+	int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV);
+
+	/*
+	 * 6-10: Version 5.4 introduced an option to address the phenomenon of
+	 * a new request for a NL mode lock being blocked.
+	 *
+	 * 6-11: If the optional EXPEDITE flag is used with the new NL mode
+	 * request, then it would be granted.  In essence, the use of this flag
+	 * tells the Lock Manager to expedite theis request by not considering
+	 * what may be in the CONVERTING or WAITING queues...  As of this
+	 * writing, the EXPEDITE flag can be used only with new requests for NL
+	 * mode locks.  This flag is not valid for conversion requests.
+	 *
+	 * A shortcut.  Earlier checks return an error if EXPEDITE is used in a
+	 * conversion or used with a non-NL requested mode.  We also know an
+	 * EXPEDITE request is always granted immediately, so now must always
+	 * be 1.  The full condition to grant an expedite request: (now &&
+	 * !conv && lkb->rqmode == DLM_LOCK_NL && (flags & EXPEDITE)) can
+	 * therefore be shortened to just checking the flag.
+	 */
+
+	if (lkb->lkb_exflags & DLM_LKF_EXPEDITE)
+		return 1;
+
+	/*
+	 * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be
+	 * added to the remaining conditions.
+	 */
+
+	if (queue_conflict(&r->res_grantqueue, lkb))
+		goto out;
+
+	/*
+	 * 6-3: By default, a conversion request is immediately granted if the
+	 * requested mode is compatible with the modes of all other granted
+	 * locks
+	 */
+
+	if (queue_conflict(&r->res_convertqueue, lkb))
+		goto out;
+
+	/*
+	 * 6-5: But the default algorithm for deciding whether to grant or
+	 * queue conversion requests does not by itself guarantee that such
+	 * requests are serviced on a "first come first serve" basis.  This, in
+	 * turn, can lead to a phenomenon known as "indefinate postponement".
+	 *
+	 * 6-7: This issue is dealt with by using the optional QUECVT flag with
+	 * the system service employed to request a lock conversion.  This flag
+	 * forces certain conversion requests to be queued, even if they are
+	 * compatible with the granted modes of other locks on the same
+	 * resource.  Thus, the use of this flag results in conversion requests
+	 * being ordered on a "first come first servce" basis.
+	 *
+	 * DCT: This condition is all about new conversions being able to occur
+	 * "in place" while the lock remains on the granted queue (assuming
+	 * nothing else conflicts.)  IOW if QUECVT isn't set, a conversion
+	 * doesn't _have_ to go onto the convert queue where it's processed in
+	 * order.  The "now" variable is necessary to distinguish converts
+	 * being received and processed for the first time now, because once a
+	 * convert is moved to the conversion queue the condition below applies
+	 * requiring fifo granting.
+	 */
+
+	if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT))
+		return 1;
+
+	/*
+	 * The NOORDER flag is set to avoid the standard vms rules on grant
+	 * order.
+	 */
+
+	if (lkb->lkb_exflags & DLM_LKF_NOORDER)
+		return 1;
+
+	/*
+	 * 6-3: Once in that queue [CONVERTING], a conversion request cannot be
+	 * granted until all other conversion requests ahead of it are granted
+	 * and/or canceled.
+	 */
+
+	if (!now && conv && first_in_list(lkb, &r->res_convertqueue))
+		return 1;
+
+	/*
+	 * 6-4: By default, a new request is immediately granted only if all
+	 * three of the following conditions are satisfied when the request is
+	 * issued:
+	 * - The queue of ungranted conversion requests for the resource is
+	 *   empty.
+	 * - The queue of ungranted new requests for the resource is empty.
+	 * - The mode of the new request is compatible with the most
+	 *   restrictive mode of all granted locks on the resource.
+	 */
+
+	if (now && !conv && list_empty(&r->res_convertqueue) &&
+	    list_empty(&r->res_waitqueue))
+		return 1;
+
+	/*
+	 * 6-4: Once a lock request is in the queue of ungranted new requests,
+	 * it cannot be granted until the queue of ungranted conversion
+	 * requests is empty, all ungranted new requests ahead of it are
+	 * granted and/or canceled, and it is compatible with the granted mode
+	 * of the most restrictive lock granted on the resource.
+	 */
+
+	if (!now && !conv && list_empty(&r->res_convertqueue) &&
+	    first_in_list(lkb, &r->res_waitqueue))
+		return 1;
+
+ out:
+	/*
+	 * The following, enabled by CONVDEADLK, departs from VMS.
+	 */
+
+	if (conv && (lkb->lkb_exflags & DLM_LKF_CONVDEADLK) &&
+	    conversion_deadlock_detect(r, lkb)) {
+		lkb->lkb_grmode = DLM_LOCK_NL;
+		lkb->lkb_sbflags |= DLM_SBF_DEMOTED;
+	}
+
+	return 0;
+}
+
+/*
+ * The ALTPR and ALTCW flags aren't traditional lock manager flags, but are a
+ * simple way to provide a big optimization to applications that can use them.
+ */
+
+static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
+{
+	uint32_t flags = lkb->lkb_exflags;
+	int rv;
+	int8_t alt = 0, rqmode = lkb->lkb_rqmode;
+
+	rv = _can_be_granted(r, lkb, now);
+	if (rv)
+		goto out;
+
+	if (lkb->lkb_sbflags & DLM_SBF_DEMOTED)
+		goto out;
+
+	if (rqmode != DLM_LOCK_PR && flags & DLM_LKF_ALTPR)
+		alt = DLM_LOCK_PR;
+	else if (rqmode != DLM_LOCK_CW && flags & DLM_LKF_ALTCW)
+		alt = DLM_LOCK_CW;
+
+	if (alt) {
+		lkb->lkb_rqmode = alt;
+		rv = _can_be_granted(r, lkb, now);
+		if (rv)
+			lkb->lkb_sbflags |= DLM_SBF_ALTMODE;
+		else
+			lkb->lkb_rqmode = rqmode;
+	}
+ out:
+	return rv;
+}
+
+static int grant_pending_convert(struct dlm_rsb *r, int high)
+{
+	struct dlm_lkb *lkb, *s;
+	int hi, demoted, quit, grant_restart, demote_restart;
+
+	quit = 0;
+ restart:
+	grant_restart = 0;
+	demote_restart = 0;
+	hi = DLM_LOCK_IV;
+
+	list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) {
+		demoted = is_demoted(lkb);
+		if (can_be_granted(r, lkb, 0)) {
+			grant_lock_pending(r, lkb);
+			grant_restart = 1;
+		} else {
+			hi = max_t(int, lkb->lkb_rqmode, hi);
+			if (!demoted && is_demoted(lkb))
+				demote_restart = 1;
+		}
+	}
+
+	if (grant_restart)
+		goto restart;
+	if (demote_restart && !quit) {
+		quit = 1;
+		goto restart;
+	}
+
+	return max_t(int, high, hi);
+}
+
+static int grant_pending_wait(struct dlm_rsb *r, int high)
+{
+	struct dlm_lkb *lkb, *s;
+
+	list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
+		if (can_be_granted(r, lkb, 0))
+			grant_lock_pending(r, lkb);
+                else
+			high = max_t(int, lkb->lkb_rqmode, high);
+	}
+
+	return high;
+}
+
+static void grant_pending_locks(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb, *s;
+	int high = DLM_LOCK_IV;
+
+	DLM_ASSERT(is_master(r), dlm_dump_rsb(r););
+
+	high = grant_pending_convert(r, high);
+	high = grant_pending_wait(r, high);
+
+	if (high == DLM_LOCK_IV)
+		return;
+
+	/*
+	 * If there are locks left on the wait/convert queue then send blocking
+	 * ASTs to granted locks based on the largest requested mode (high)
+	 * found above. FIXME: highbast < high comparison not valid for PR/CW.
+	 */
+
+	list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) {
+		if (lkb->lkb_bastaddr && (lkb->lkb_highbast < high) &&
+		    !__dlm_compat_matrix[lkb->lkb_grmode+1][high+1]) {
+			queue_bast(r, lkb, high);
+			lkb->lkb_highbast = high;
+		}
+	}
+}
+
+static void send_bast_queue(struct dlm_rsb *r, struct list_head *head,
+			    struct dlm_lkb *lkb)
+{
+	struct dlm_lkb *gr;
+
+	list_for_each_entry(gr, head, lkb_statequeue) {
+		if (gr->lkb_bastaddr &&
+		    gr->lkb_highbast < lkb->lkb_rqmode &&
+		    !modes_compat(gr, lkb)) {
+			queue_bast(r, gr, lkb->lkb_rqmode);
+			gr->lkb_highbast = lkb->lkb_rqmode;
+		}
+	}
+}
+
+static void send_blocking_asts(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	send_bast_queue(r, &r->res_grantqueue, lkb);
+}
+
+static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	send_bast_queue(r, &r->res_grantqueue, lkb);
+	send_bast_queue(r, &r->res_convertqueue, lkb);
+}
+
+/* set_master(r, lkb) -- set the master nodeid of a resource
+
+   The purpose of this function is to set the nodeid field in the given
+   lkb using the nodeid field in the given rsb.  If the rsb's nodeid is
+   known, it can just be copied to the lkb and the function will return
+   0.  If the rsb's nodeid is _not_ known, it needs to be looked up
+   before it can be copied to the lkb.
+
+   When the rsb nodeid is being looked up remotely, the initial lkb
+   causing the lookup is kept on the ls_waiters list waiting for the
+   lookup reply.  Other lkb's waiting for the same rsb lookup are kept
+   on the rsb's res_lookup list until the master is verified.
+
+   Return values:
+   0: nodeid is set in rsb/lkb and the caller should go ahead and use it
+   1: the rsb master is not available and the lkb has been placed on
+      a wait queue
+*/
+
+static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls = r->res_ls;
+	int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+
+	if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {
+		rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
+		r->res_first_lkid = lkb->lkb_id;
+		lkb->lkb_nodeid = r->res_nodeid;
+		return 0;
+	}
+
+	if (r->res_first_lkid && r->res_first_lkid != lkb->lkb_id) {
+		list_add_tail(&lkb->lkb_rsb_lookup, &r->res_lookup);
+		return 1;
+	}
+
+	if (r->res_nodeid == 0) {
+		lkb->lkb_nodeid = 0;
+		return 0;
+	}
+
+	if (r->res_nodeid > 0) {
+		lkb->lkb_nodeid = r->res_nodeid;
+		return 0;
+	}
+
+	DLM_ASSERT(r->res_nodeid == -1, dlm_dump_rsb(r););
+
+	dir_nodeid = dlm_dir_nodeid(r);
+
+	if (dir_nodeid != our_nodeid) {
+		r->res_first_lkid = lkb->lkb_id;
+		send_lookup(r, lkb);
+		return 1;
+	}
+
+	for (;;) {
+		/* It's possible for dlm_scand to remove an old rsb for
+		   this same resource from the toss list, us to create
+		   a new one, look up the master locally, and find it
+		   already exists just before dlm_scand does the
+		   dir_remove() on the previous rsb. */
+
+		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
+				       r->res_length, &ret_nodeid);
+		if (!error)
+			break;
+		log_debug(ls, "dir_lookup error %d %s", error, r->res_name);
+		schedule();
+	}
+
+	if (ret_nodeid == our_nodeid) {
+		r->res_first_lkid = 0;
+		r->res_nodeid = 0;
+		lkb->lkb_nodeid = 0;
+	} else {
+		r->res_first_lkid = lkb->lkb_id;
+		r->res_nodeid = ret_nodeid;
+		lkb->lkb_nodeid = ret_nodeid;
+	}
+	return 0;
+}
+
+static void process_lookup_list(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) {
+		list_del(&lkb->lkb_rsb_lookup);
+		_request_lock(r, lkb);
+		schedule();
+	}
+}
+
+/* confirm_master -- confirm (or deny) an rsb's master nodeid */
+
+static void confirm_master(struct dlm_rsb *r, int error)
+{
+	struct dlm_lkb *lkb;
+
+	if (!r->res_first_lkid)
+		return;
+
+	switch (error) {
+	case 0:
+	case -EINPROGRESS:
+		r->res_first_lkid = 0;
+		process_lookup_list(r);
+		break;
+
+	case -EAGAIN:
+		/* the remote master didn't queue our NOQUEUE request;
+		   make a waiting lkb the first_lkid */
+
+		r->res_first_lkid = 0;
+
+		if (!list_empty(&r->res_lookup)) {
+			lkb = list_entry(r->res_lookup.next, struct dlm_lkb,
+					 lkb_rsb_lookup);
+			list_del(&lkb->lkb_rsb_lookup);
+			r->res_first_lkid = lkb->lkb_id;
+			_request_lock(r, lkb);
+		} else
+			r->res_nodeid = -1;
+		break;
+
+	default:
+		log_error(r->res_ls, "confirm_master unknown error %d", error);
+	}
+}
+
+static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
+			 int namelen, uint32_t parent_lkid, void *ast,
+			 void *astarg, void *bast, struct dlm_args *args)
+{
+	int rv = -EINVAL;
+
+	/* check for invalid arg usage */
+
+	if (mode < 0 || mode > DLM_LOCK_EX)
+		goto out;
+
+	if (!(flags & DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN))
+		goto out;
+
+	if (flags & DLM_LKF_CANCEL)
+		goto out;
+
+	if (flags & DLM_LKF_QUECVT && !(flags & DLM_LKF_CONVERT))
+		goto out;
+
+	if (flags & DLM_LKF_CONVDEADLK && !(flags & DLM_LKF_CONVERT))
+		goto out;
+
+	if (flags & DLM_LKF_CONVDEADLK && flags & DLM_LKF_NOQUEUE)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_CONVERT)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_QUECVT)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_NOQUEUE)
+		goto out;
+
+	if (flags & DLM_LKF_EXPEDITE && mode != DLM_LOCK_NL)
+		goto out;
+
+	if (!ast || !lksb)
+		goto out;
+
+	if (flags & DLM_LKF_VALBLK && !lksb->sb_lvbptr)
+		goto out;
+
+	/* parent/child locks not yet supported */
+	if (parent_lkid)
+		goto out;
+
+	if (flags & DLM_LKF_CONVERT && !lksb->sb_lkid)
+		goto out;
+
+	/* these args will be copied to the lkb in validate_lock_args,
+	   it cannot be done now because when converting locks, fields in
+	   an active lkb cannot be modified before locking the rsb */
+
+	args->flags = flags;
+	args->astaddr = ast;
+	args->astparam = (long) astarg;
+	args->bastaddr = bast;
+	args->mode = mode;
+	args->lksb = lksb;
+	rv = 0;
+ out:
+	return rv;
+}
+
+static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)
+{
+	if (flags & ~(DLM_LKF_CANCEL | DLM_LKF_VALBLK | DLM_LKF_IVVALBLK |
+ 		      DLM_LKF_FORCEUNLOCK))
+		return -EINVAL;
+
+	args->flags = flags;
+	args->astparam = (long) astarg;
+	return 0;
+}
+
+static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+			      struct dlm_args *args)
+{
+	int rv = -EINVAL;
+
+	if (args->flags & DLM_LKF_CONVERT) {
+		if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+			goto out;
+
+		if (args->flags & DLM_LKF_QUECVT &&
+		    !__quecvt_compat_matrix[lkb->lkb_grmode+1][args->mode+1])
+			goto out;
+
+		rv = -EBUSY;
+		if (lkb->lkb_status != DLM_LKSTS_GRANTED)
+			goto out;
+
+		if (lkb->lkb_wait_type)
+			goto out;
+	}
+
+	lkb->lkb_exflags = args->flags;
+	lkb->lkb_sbflags = 0;
+	lkb->lkb_astaddr = args->astaddr;
+	lkb->lkb_astparam = args->astparam;
+	lkb->lkb_bastaddr = args->bastaddr;
+	lkb->lkb_rqmode = args->mode;
+	lkb->lkb_lksb = args->lksb;
+	lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
+	lkb->lkb_ownpid = (int) current->pid;
+	rv = 0;
+ out:
+	return rv;
+}
+
+static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
+{
+	int rv = -EINVAL;
+
+	if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+		goto out;
+
+	if (args->flags & DLM_LKF_FORCEUNLOCK)
+		goto out_ok;
+
+	if (args->flags & DLM_LKF_CANCEL &&
+	    lkb->lkb_status == DLM_LKSTS_GRANTED)
+		goto out;
+
+	if (!(args->flags & DLM_LKF_CANCEL) &&
+	    lkb->lkb_status != DLM_LKSTS_GRANTED)
+		goto out;
+
+	rv = -EBUSY;
+	if (lkb->lkb_wait_type)
+		goto out;
+
+ out_ok:
+	lkb->lkb_exflags = args->flags;
+	lkb->lkb_sbflags = 0;
+	lkb->lkb_astparam = args->astparam;
+
+	rv = 0;
+ out:
+	return rv;
+}
+
+/*
+ * Four stage 4 varieties:
+ * do_request(), do_convert(), do_unlock(), do_cancel()
+ * These are called on the master node for the given lock and
+ * from the central locking logic.
+ */
+
+static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error = 0;
+
+	if (can_be_granted(r, lkb, 1)) {
+		grant_lock(r, lkb);
+		queue_cast(r, lkb, 0);
+		goto out;
+	}
+
+	if (can_be_queued(lkb)) {
+		error = -EINPROGRESS;
+		add_lkb(r, lkb, DLM_LKSTS_WAITING);
+		send_blocking_asts(r, lkb);
+		goto out;
+	}
+
+	error = -EAGAIN;
+	if (force_blocking_asts(lkb))
+		send_blocking_asts_all(r, lkb);
+	queue_cast(r, lkb, -EAGAIN);
+
+ out:
+	return error;
+}
+
+static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error = 0;
+
+	/* changing an existing lock may allow others to be granted */
+
+	if (can_be_granted(r, lkb, 1)) {
+		grant_lock(r, lkb);
+		queue_cast(r, lkb, 0);
+		grant_pending_locks(r);
+		goto out;
+	}
+
+	if (can_be_queued(lkb)) {
+		if (is_demoted(lkb))
+			grant_pending_locks(r);
+		error = -EINPROGRESS;
+		del_lkb(r, lkb);
+		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
+		send_blocking_asts(r, lkb);
+		goto out;
+	}
+
+	error = -EAGAIN;
+	if (force_blocking_asts(lkb))
+		send_blocking_asts_all(r, lkb);
+	queue_cast(r, lkb, -EAGAIN);
+
+ out:
+	return error;
+}
+
+static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	remove_lock(r, lkb);
+	queue_cast(r, lkb, -DLM_EUNLOCK);
+	grant_pending_locks(r);
+	return -DLM_EUNLOCK;
+}
+
+/* FIXME: if revert_lock() finds that the lkb is granted, we should
+   skip the queue_cast(ECANCEL).  It indicates that the request/convert
+   completed (and queued a normal ast) just before the cancel; we don't
+   want to clobber the sb_result for the normal ast with ECANCEL. */
+ 
+static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	revert_lock(r, lkb);
+	queue_cast(r, lkb, -DLM_ECANCEL);
+	grant_pending_locks(r);
+	return -DLM_ECANCEL;
+}
+
+/*
+ * Four stage 3 varieties:
+ * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock()
+ */
+
+/* add a new lkb to a possibly new rsb, called by requesting process */
+
+static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	/* set_master: sets lkb nodeid from r */
+
+	error = set_master(r, lkb);
+	if (error < 0)
+		goto out;
+	if (error) {
+		error = 0;
+		goto out;
+	}
+
+	if (is_remote(r))
+		/* receive_request() calls do_request() on remote node */
+		error = send_request(r, lkb);
+	else
+		error = do_request(r, lkb);
+ out:
+	return error;
+}
+
+/* change some property of an existing lkb, e.g. mode */
+
+static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	if (is_remote(r))
+		/* receive_convert() calls do_convert() on remote node */
+		error = send_convert(r, lkb);
+	else
+		error = do_convert(r, lkb);
+
+	return error;
+}
+
+/* remove an existing lkb from the granted queue */
+
+static int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	if (is_remote(r))
+		/* receive_unlock() calls do_unlock() on remote node */
+		error = send_unlock(r, lkb);
+	else
+		error = do_unlock(r, lkb);
+
+	return error;
+}
+
+/* remove an existing lkb from the convert or wait queue */
+
+static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	if (is_remote(r))
+		/* receive_cancel() calls do_cancel() on remote node */
+		error = send_cancel(r, lkb);
+	else
+		error = do_cancel(r, lkb);
+
+	return error;
+}
+
+/*
+ * Four stage 2 varieties:
+ * request_lock(), convert_lock(), unlock_lock(), cancel_lock()
+ */
+
+static int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, char *name,
+			int len, struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	error = validate_lock_args(ls, lkb, args);
+	if (error)
+		goto out;
+
+	error = find_rsb(ls, name, len, R_CREATE, &r);
+	if (error)
+		goto out;
+
+	lock_rsb(r);
+
+	attach_lkb(r, lkb);
+	lkb->lkb_lksb->sb_lkid = lkb->lkb_id;
+
+	error = _request_lock(r, lkb);
+
+	unlock_rsb(r);
+	put_rsb(r);
+
+ out:
+	return error;
+}
+
+static int convert_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+			struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = validate_lock_args(ls, lkb, args);
+	if (error)
+		goto out;
+
+	error = _convert_lock(r, lkb);
+ out:
+	unlock_rsb(r);
+	put_rsb(r);
+	return error;
+}
+
+static int unlock_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+		       struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = validate_unlock_args(lkb, args);
+	if (error)
+		goto out;
+
+	error = _unlock_lock(r, lkb);
+ out:
+	unlock_rsb(r);
+	put_rsb(r);
+	return error;
+}
+
+static int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+		       struct dlm_args *args)
+{
+	struct dlm_rsb *r;
+	int error;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = validate_unlock_args(lkb, args);
+	if (error)
+		goto out;
+
+	error = _cancel_lock(r, lkb);
+ out:
+	unlock_rsb(r);
+	put_rsb(r);
+	return error;
+}
+
+/*
+ * Two stage 1 varieties:  dlm_lock() and dlm_unlock()
+ */
+
+int dlm_lock(dlm_lockspace_t *lockspace,
+	     int mode,
+	     struct dlm_lksb *lksb,
+	     uint32_t flags,
+	     void *name,
+	     unsigned int namelen,
+	     uint32_t parent_lkid,
+	     void (*ast) (void *astarg),
+	     void *astarg,
+	     void (*bast) (void *astarg, int mode))
+{
+	struct dlm_ls *ls;
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	int error, convert = flags & DLM_LKF_CONVERT;
+
+	ls = dlm_find_lockspace_local(lockspace);
+	if (!ls)
+		return -EINVAL;
+
+	lock_recovery(ls);
+
+	if (convert)
+		error = find_lkb(ls, lksb->sb_lkid, &lkb);
+	else
+		error = create_lkb(ls, &lkb);
+
+	if (error)
+		goto out;
+
+	error = set_lock_args(mode, lksb, flags, namelen, parent_lkid, ast,
+			      astarg, bast, &args);
+	if (error)
+		goto out_put;
+
+	if (convert)
+		error = convert_lock(ls, lkb, &args);
+	else
+		error = request_lock(ls, lkb, name, namelen, &args);
+
+	if (error == -EINPROGRESS)
+		error = 0;
+ out_put:
+	if (convert || error)
+		__put_lkb(ls, lkb);
+	if (error == -EAGAIN)
+		error = 0;
+ out:
+	unlock_recovery(ls);
+	dlm_put_lockspace(ls);
+	return error;
+}
+
+int dlm_unlock(dlm_lockspace_t *lockspace,
+	       uint32_t lkid,
+	       uint32_t flags,
+	       struct dlm_lksb *lksb,
+	       void *astarg)
+{
+	struct dlm_ls *ls;
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	int error;
+
+	ls = dlm_find_lockspace_local(lockspace);
+	if (!ls)
+		return -EINVAL;
+
+	lock_recovery(ls);
+
+	error = find_lkb(ls, lkid, &lkb);
+	if (error)
+		goto out;
+
+	error = set_unlock_args(flags, astarg, &args);
+	if (error)
+		goto out_put;
+
+	if (flags & DLM_LKF_CANCEL)
+		error = cancel_lock(ls, lkb, &args);
+	else
+		error = unlock_lock(ls, lkb, &args);
+
+	if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)
+		error = 0;
+ out_put:
+	dlm_put_lkb(lkb);
+ out:
+	unlock_recovery(ls);
+	dlm_put_lockspace(ls);
+	return error;
+}
+
+/*
+ * send/receive routines for remote operations and replies
+ *
+ * send_args
+ * send_common
+ * send_request			receive_request
+ * send_convert			receive_convert
+ * send_unlock			receive_unlock
+ * send_cancel			receive_cancel
+ * send_grant			receive_grant
+ * send_bast			receive_bast
+ * send_lookup			receive_lookup
+ * send_remove			receive_remove
+ *
+ * 				send_common_reply
+ * receive_request_reply	send_request_reply
+ * receive_convert_reply	send_convert_reply
+ * receive_unlock_reply		send_unlock_reply
+ * receive_cancel_reply		send_cancel_reply
+ * receive_lookup_reply		send_lookup_reply
+ */
+
+static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			  int to_nodeid, int mstype,
+			  struct dlm_message **ms_ret,
+			  struct dlm_mhandle **mh_ret)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	char *mb;
+	int mb_len = sizeof(struct dlm_message);
+
+	switch (mstype) {
+	case DLM_MSG_REQUEST:
+	case DLM_MSG_LOOKUP:
+	case DLM_MSG_REMOVE:
+		mb_len += r->res_length;
+		break;
+	case DLM_MSG_CONVERT:
+	case DLM_MSG_UNLOCK:
+	case DLM_MSG_REQUEST_REPLY:
+	case DLM_MSG_CONVERT_REPLY:
+	case DLM_MSG_GRANT:
+		if (lkb && lkb->lkb_lvbptr)
+			mb_len += r->res_ls->ls_lvblen;
+		break;
+	}
+
+	/* get_buffer gives us a message handle (mh) that we need to
+	   pass into lowcomms_commit and a message buffer (mb) that we
+	   write our data into */
+
+	mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
+	if (!mh)
+		return -ENOBUFS;
+
+	memset(mb, 0, mb_len);
+
+	ms = (struct dlm_message *) mb;
+
+	ms->m_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+	ms->m_header.h_lockspace = r->res_ls->ls_global_id;
+	ms->m_header.h_nodeid = dlm_our_nodeid();
+	ms->m_header.h_length = mb_len;
+	ms->m_header.h_cmd = DLM_MSG;
+
+	ms->m_type = mstype;
+
+	*mh_ret = mh;
+	*ms_ret = ms;
+	return 0;
+}
+
+/* further lowcomms enhancements or alternate implementations may make
+   the return value from this function useful at some point */
+
+static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms)
+{
+	dlm_message_out(ms);
+	dlm_lowcomms_commit_buffer(mh);
+	return 0;
+}
+
+static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
+		      struct dlm_message *ms)
+{
+	ms->m_nodeid   = lkb->lkb_nodeid;
+	ms->m_pid      = lkb->lkb_ownpid;
+	ms->m_lkid     = lkb->lkb_id;
+	ms->m_remid    = lkb->lkb_remid;
+	ms->m_exflags  = lkb->lkb_exflags;
+	ms->m_sbflags  = lkb->lkb_sbflags;
+	ms->m_flags    = lkb->lkb_flags;
+	ms->m_lvbseq   = lkb->lkb_lvbseq;
+	ms->m_status   = lkb->lkb_status;
+	ms->m_grmode   = lkb->lkb_grmode;
+	ms->m_rqmode   = lkb->lkb_rqmode;
+	ms->m_hash     = r->res_hash;
+
+	/* m_result and m_bastmode are set from function args,
+	   not from lkb fields */
+
+	if (lkb->lkb_bastaddr)
+		ms->m_asts |= AST_BAST;
+	if (lkb->lkb_astaddr)
+		ms->m_asts |= AST_COMP;
+
+	if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP)
+		memcpy(ms->m_extra, r->res_name, r->res_length);
+
+	else if (lkb->lkb_lvbptr)
+		memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+
+}
+
+static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	add_to_waiters(lkb, mstype);
+
+	to_nodeid = r->res_nodeid;
+
+	error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+	if (error)
+		goto fail;
+
+	send_args(r, lkb, ms);
+
+	error = send_message(mh, ms);
+	if (error)
+		goto fail;
+	return 0;
+
+ fail:
+	remove_from_waiters(lkb);
+	return error;
+}
+
+static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	return send_common(r, lkb, DLM_MSG_REQUEST);
+}
+
+static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	int error;
+
+	error = send_common(r, lkb, DLM_MSG_CONVERT);
+
+	/* down conversions go without a reply from the master */
+	if (!error && down_conversion(lkb)) {
+		remove_from_waiters(lkb);
+		r->res_ls->ls_stub_ms.m_result = 0;
+		r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags;
+		__receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms);
+	}
+
+	return error;
+}
+
+/* FIXME: if this lkb is the only lock we hold on the rsb, then set
+   MASTER_UNCERTAIN to force the next request on the rsb to confirm
+   that the master is still correct. */
+
+static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	return send_common(r, lkb, DLM_MSG_UNLOCK);
+}
+
+static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	return send_common(r, lkb, DLM_MSG_CANCEL);
+}
+
+static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = lkb->lkb_nodeid;
+
+	error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh);
+	if (error)
+		goto out;
+
+	send_args(r, lkb, ms);
+
+	ms->m_result = 0;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = lkb->lkb_nodeid;
+
+	error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh);
+	if (error)
+		goto out;
+
+	send_args(r, lkb, ms);
+
+	ms->m_bastmode = mode;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	add_to_waiters(lkb, DLM_MSG_LOOKUP);
+
+	to_nodeid = dlm_dir_nodeid(r);
+
+	error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh);
+	if (error)
+		goto fail;
+
+	send_args(r, lkb, ms);
+
+	error = send_message(mh, ms);
+	if (error)
+		goto fail;
+	return 0;
+
+ fail:
+	remove_from_waiters(lkb);
+	return error;
+}
+
+static int send_remove(struct dlm_rsb *r)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = dlm_dir_nodeid(r);
+
+	error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh);
+	if (error)
+		goto out;
+
+	memcpy(ms->m_extra, r->res_name, r->res_length);
+	ms->m_hash = r->res_hash;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			     int mstype, int rv)
+{
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int to_nodeid, error;
+
+	to_nodeid = lkb->lkb_nodeid;
+
+	error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+	if (error)
+		goto out;
+
+	send_args(r, lkb, ms);
+
+	ms->m_result = rv;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+static int send_request_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_REQUEST_REPLY, rv);
+}
+
+static int send_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_CONVERT_REPLY, rv);
+}
+
+static int send_unlock_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_UNLOCK_REPLY, rv);
+}
+
+static int send_cancel_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+	return send_common_reply(r, lkb, DLM_MSG_CANCEL_REPLY, rv);
+}
+
+static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in,
+			     int ret_nodeid, int rv)
+{
+	struct dlm_rsb *r = &ls->ls_stub_rsb;
+	struct dlm_message *ms;
+	struct dlm_mhandle *mh;
+	int error, nodeid = ms_in->m_header.h_nodeid;
+
+	error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh);
+	if (error)
+		goto out;
+
+	ms->m_lkid = ms_in->m_lkid;
+	ms->m_result = rv;
+	ms->m_nodeid = ret_nodeid;
+
+	error = send_message(mh, ms);
+ out:
+	return error;
+}
+
+/* which args we save from a received message depends heavily on the type
+   of message, unlike the send side where we can safely send everything about
+   the lkb for any type of message */
+
+static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	lkb->lkb_exflags = ms->m_exflags;
+	lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
+		         (ms->m_flags & 0x0000FFFF);
+}
+
+static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	lkb->lkb_sbflags = ms->m_sbflags;
+	lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
+		         (ms->m_flags & 0x0000FFFF);
+}
+
+static int receive_extralen(struct dlm_message *ms)
+{
+	return (ms->m_header.h_length - sizeof(struct dlm_message));
+}
+
+static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb,
+		       struct dlm_message *ms)
+{
+	int len;
+
+	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+		if (!lkb->lkb_lvbptr)
+			lkb->lkb_lvbptr = allocate_lvb(ls);
+		if (!lkb->lkb_lvbptr)
+			return -ENOMEM;
+		len = receive_extralen(ms);
+		memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
+	}
+	return 0;
+}
+
+static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+				struct dlm_message *ms)
+{
+	lkb->lkb_nodeid = ms->m_header.h_nodeid;
+	lkb->lkb_ownpid = ms->m_pid;
+	lkb->lkb_remid = ms->m_lkid;
+	lkb->lkb_grmode = DLM_LOCK_IV;
+	lkb->lkb_rqmode = ms->m_rqmode;
+	lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST);
+	lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP);
+
+	DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
+
+	if (receive_lvb(ls, lkb, ms))
+		return -ENOMEM;
+
+	return 0;
+}
+
+static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+				struct dlm_message *ms)
+{
+	if (lkb->lkb_nodeid != ms->m_header.h_nodeid) {
+		log_error(ls, "convert_args nodeid %d %d lkid %x %x",
+			  lkb->lkb_nodeid, ms->m_header.h_nodeid,
+			  lkb->lkb_id, lkb->lkb_remid);
+		return -EINVAL;
+	}
+
+	if (!is_master_copy(lkb))
+		return -EINVAL;
+
+	if (lkb->lkb_status != DLM_LKSTS_GRANTED)
+		return -EBUSY;
+
+	if (receive_lvb(ls, lkb, ms))
+		return -ENOMEM;
+
+	lkb->lkb_rqmode = ms->m_rqmode;
+	lkb->lkb_lvbseq = ms->m_lvbseq;
+
+	return 0;
+}
+
+static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+			       struct dlm_message *ms)
+{
+	if (!is_master_copy(lkb))
+		return -EINVAL;
+	if (receive_lvb(ls, lkb, ms))
+		return -ENOMEM;
+	return 0;
+}
+
+/* We fill in the stub-lkb fields with the info that send_xxxx_reply()
+   uses to send a reply and that the remote end uses to process the reply. */
+
+static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb = &ls->ls_stub_lkb;
+	lkb->lkb_nodeid = ms->m_header.h_nodeid;
+	lkb->lkb_remid = ms->m_lkid;
+}
+
+static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, namelen;
+
+	error = create_lkb(ls, &lkb);
+	if (error)
+		goto fail;
+
+	receive_flags(lkb, ms);
+	lkb->lkb_flags |= DLM_IFL_MSTCPY;
+	error = receive_request_args(ls, lkb, ms);
+	if (error) {
+		__put_lkb(ls, lkb);
+		goto fail;
+	}
+
+	namelen = receive_extralen(ms);
+
+	error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &r);
+	if (error) {
+		__put_lkb(ls, lkb);
+		goto fail;
+	}
+
+	lock_rsb(r);
+
+	attach_lkb(r, lkb);
+	error = do_request(r, lkb);
+	send_request_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+
+	if (error == -EINPROGRESS)
+		error = 0;
+	if (error)
+		dlm_put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, reply = 1;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error)
+		goto fail;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	receive_flags(lkb, ms);
+	error = receive_convert_args(ls, lkb, ms);
+	if (error)
+		goto out;
+	reply = !down_conversion(lkb);
+
+	error = do_convert(r, lkb);
+ out:
+	if (reply)
+		send_convert_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	dlm_put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_convert_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error)
+		goto fail;
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	receive_flags(lkb, ms);
+	error = receive_unlock_args(ls, lkb, ms);
+	if (error)
+		goto out;
+
+	error = do_unlock(r, lkb);
+ out:
+	send_unlock_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	dlm_put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_unlock_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error)
+		goto fail;
+
+	receive_flags(lkb, ms);
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	error = do_cancel(r, lkb);
+	send_cancel_reply(r, lkb, error);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	dlm_put_lkb(lkb);
+	return;
+
+ fail:
+	setup_stub_lkb(ls, ms);
+	send_cancel_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_grant no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	receive_flags_reply(lkb, ms);
+	grant_lock_pc(r, lkb, ms);
+	queue_cast(r, lkb, 0);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	dlm_put_lkb(lkb);
+}
+
+static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_bast no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	queue_bast(r, lkb, ms->m_bastmode);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	dlm_put_lkb(lkb);
+}
+
+static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	int len, error, ret_nodeid, dir_nodeid, from_nodeid, our_nodeid;
+
+	from_nodeid = ms->m_header.h_nodeid;
+	our_nodeid = dlm_our_nodeid();
+
+	len = receive_extralen(ms);
+
+	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
+	if (dir_nodeid != our_nodeid) {
+		log_error(ls, "lookup dir_nodeid %d from %d",
+			  dir_nodeid, from_nodeid);
+		error = -EINVAL;
+		ret_nodeid = -1;
+		goto out;
+	}
+
+	error = dlm_dir_lookup(ls, from_nodeid, ms->m_extra, len, &ret_nodeid);
+
+	/* Optimization: we're master so treat lookup as a request */
+	if (!error && ret_nodeid == our_nodeid) {
+		receive_request(ls, ms);
+		return;
+	}
+ out:
+	send_lookup_reply(ls, ms, ret_nodeid, error);
+}
+
+static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	int len, dir_nodeid, from_nodeid;
+
+	from_nodeid = ms->m_header.h_nodeid;
+
+	len = receive_extralen(ms);
+
+	dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
+	if (dir_nodeid != dlm_our_nodeid()) {
+		log_error(ls, "remove dir entry dir_nodeid %d from %d",
+			  dir_nodeid, from_nodeid);
+		return;
+	}
+
+	dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);
+}
+
+static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, mstype;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_request_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	mstype = lkb->lkb_wait_type;
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_request_reply not on waiters");
+		goto out;
+	}
+
+	/* this is the value returned from do_request() on the master */
+	error = ms->m_result;
+
+	r = lkb->lkb_resource;
+	hold_rsb(r);
+	lock_rsb(r);
+
+	/* Optimization: the dir node was also the master, so it took our
+	   lookup as a request and sent request reply instead of lookup reply */
+	if (mstype == DLM_MSG_LOOKUP) {
+		r->res_nodeid = ms->m_header.h_nodeid;
+		lkb->lkb_nodeid = r->res_nodeid;
+	}
+
+	switch (error) {
+	case -EAGAIN:
+		/* request would block (be queued) on remote master;
+		   the unhold undoes the original ref from create_lkb()
+		   so it leads to the lkb being freed */
+		queue_cast(r, lkb, -EAGAIN);
+		confirm_master(r, -EAGAIN);
+		unhold_lkb(lkb);
+		break;
+
+	case -EINPROGRESS:
+	case 0:
+		/* request was queued or granted on remote master */
+		receive_flags_reply(lkb, ms);
+		lkb->lkb_remid = ms->m_lkid;
+		if (error)
+			add_lkb(r, lkb, DLM_LKSTS_WAITING);
+		else {
+			grant_lock_pc(r, lkb, ms);
+			queue_cast(r, lkb, 0);
+		}
+		confirm_master(r, error);
+		break;
+
+	case -EBADR:
+	case -ENOTBLK:
+		/* find_rsb failed to find rsb or rsb wasn't master */
+		r->res_nodeid = -1;
+		lkb->lkb_nodeid = -1;
+		_request_lock(r, lkb);
+		break;
+
+	default:
+		log_error(ls, "receive_request_reply error %d", error);
+	}
+
+	unlock_rsb(r);
+	put_rsb(r);
+ out:
+	dlm_put_lkb(lkb);
+}
+
+static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+				    struct dlm_message *ms)
+{
+	int error = ms->m_result;
+
+	/* this is the value returned from do_convert() on the master */
+
+	switch (error) {
+	case -EAGAIN:
+		/* convert would block (be queued) on remote master */
+		queue_cast(r, lkb, -EAGAIN);
+		break;
+
+	case -EINPROGRESS:
+		/* convert was queued on remote master */
+		del_lkb(r, lkb);
+		add_lkb(r, lkb, DLM_LKSTS_CONVERT);
+		break;
+
+	case 0:
+		/* convert was granted on remote master */
+		receive_flags_reply(lkb, ms);
+		grant_lock_pc(r, lkb, ms);
+		queue_cast(r, lkb, 0);
+		break;
+
+	default:
+		log_error(r->res_ls, "receive_convert_reply error %d", error);
+	}
+}
+
+static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	struct dlm_rsb *r = lkb->lkb_resource;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	__receive_convert_reply(r, lkb, ms);
+
+	unlock_rsb(r);
+	put_rsb(r);
+}
+
+static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_convert_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_convert_reply not on waiters");
+		goto out;
+	}
+
+	_receive_convert_reply(lkb, ms);
+ out:
+	dlm_put_lkb(lkb);
+}
+
+static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	struct dlm_rsb *r = lkb->lkb_resource;
+	int error = ms->m_result;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	/* this is the value returned from do_unlock() on the master */
+
+	switch (error) {
+	case -DLM_EUNLOCK:
+		receive_flags_reply(lkb, ms);
+		remove_lock_pc(r, lkb);
+		queue_cast(r, lkb, -DLM_EUNLOCK);
+		break;
+	default:
+		log_error(r->res_ls, "receive_unlock_reply error %d", error);
+	}
+
+	unlock_rsb(r);
+	put_rsb(r);
+}
+
+static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_unlock_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_unlock_reply not on waiters");
+		goto out;
+	}
+
+	_receive_unlock_reply(lkb, ms);
+ out:
+	dlm_put_lkb(lkb);
+}
+
+static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+	struct dlm_rsb *r = lkb->lkb_resource;
+	int error = ms->m_result;
+
+	hold_rsb(r);
+	lock_rsb(r);
+
+	/* this is the value returned from do_cancel() on the master */
+
+	switch (error) {
+	case -DLM_ECANCEL:
+		receive_flags_reply(lkb, ms);
+		revert_lock_pc(r, lkb);
+		queue_cast(r, lkb, -DLM_ECANCEL);
+		break;
+	default:
+		log_error(r->res_ls, "receive_cancel_reply error %d", error);
+	}
+
+	unlock_rsb(r);
+	put_rsb(r);
+}
+
+static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, ms->m_remid, &lkb);
+	if (error) {
+		log_error(ls, "receive_cancel_reply no lkb");
+		return;
+	}
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_cancel_reply not on waiters");
+		goto out;
+	}
+
+	_receive_cancel_reply(lkb, ms);
+ out:
+	dlm_put_lkb(lkb);
+}
+
+static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error, ret_nodeid;
+
+	error = find_lkb(ls, ms->m_lkid, &lkb);
+	if (error) {
+		log_error(ls, "receive_lookup_reply no lkb");
+		return;
+	}
+
+	error = remove_from_waiters(lkb);
+	if (error) {
+		log_error(ls, "receive_lookup_reply not on waiters");
+		goto out;
+	}
+
+	/* this is the value returned by dlm_dir_lookup on dir node
+	   FIXME: will a non-zero error ever be returned? */
+	error = ms->m_result;
+
+	r = lkb->lkb_resource;
+	hold_rsb(r);
+	lock_rsb(r);
+
+	ret_nodeid = ms->m_nodeid;
+	if (ret_nodeid == dlm_our_nodeid()) {
+		r->res_nodeid = 0;
+		ret_nodeid = 0;
+		r->res_first_lkid = 0;
+	} else {
+		/* set_master() will copy res_nodeid to lkb_nodeid */
+		r->res_nodeid = ret_nodeid;
+	}
+
+	_request_lock(r, lkb);
+
+	if (!ret_nodeid)
+		process_lookup_list(r);
+
+	unlock_rsb(r);
+	put_rsb(r);
+ out:
+	dlm_put_lkb(lkb);
+}
+
+int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
+{
+	struct dlm_message *ms = (struct dlm_message *) hd;
+	struct dlm_ls *ls;
+	int error;
+
+	if (!recovery)
+		dlm_message_in(ms);
+
+	ls = dlm_find_lockspace_global(hd->h_lockspace);
+	if (!ls) {
+		log_print("drop message %d from %d for unknown lockspace %d",
+			  ms->m_type, nodeid, hd->h_lockspace);
+		return -EINVAL;
+	}
+
+	/* recovery may have just ended leaving a bunch of backed-up requests
+	   in the requestqueue; wait while dlm_recoverd clears them */
+
+	if (!recovery)
+		dlm_wait_requestqueue(ls);
+
+	/* recovery may have just started while there were a bunch of
+	   in-flight requests -- save them in requestqueue to be processed
+	   after recovery.  we can't let dlm_recvd block on the recovery
+	   lock.  if dlm_recoverd is calling this function to clear the
+	   requestqueue, it needs to be interrupted (-EINTR) if another
+	   recovery operation is starting. */
+
+	while (1) {
+		if (dlm_locking_stopped(ls)) {
+			if (!recovery)
+				dlm_add_requestqueue(ls, nodeid, hd);
+			error = -EINTR;
+			goto out;
+		}
+
+		if (lock_recovery_try(ls))
+			break;
+		schedule();
+	}
+
+	switch (ms->m_type) {
+
+	/* messages sent to a master node */
+
+	case DLM_MSG_REQUEST:
+		receive_request(ls, ms);
+		break;
+
+	case DLM_MSG_CONVERT:
+		receive_convert(ls, ms);
+		break;
+
+	case DLM_MSG_UNLOCK:
+		receive_unlock(ls, ms);
+		break;
+
+	case DLM_MSG_CANCEL:
+		receive_cancel(ls, ms);
+		break;
+
+	/* messages sent from a master node (replies to above) */
+
+	case DLM_MSG_REQUEST_REPLY:
+		receive_request_reply(ls, ms);
+		break;
+
+	case DLM_MSG_CONVERT_REPLY:
+		receive_convert_reply(ls, ms);
+		break;
+
+	case DLM_MSG_UNLOCK_REPLY:
+		receive_unlock_reply(ls, ms);
+		break;
+
+	case DLM_MSG_CANCEL_REPLY:
+		receive_cancel_reply(ls, ms);
+		break;
+
+	/* messages sent from a master node (only two types of async msg) */
+
+	case DLM_MSG_GRANT:
+		receive_grant(ls, ms);
+		break;
+
+	case DLM_MSG_BAST:
+		receive_bast(ls, ms);
+		break;
+
+	/* messages sent to a dir node */
+
+	case DLM_MSG_LOOKUP:
+		receive_lookup(ls, ms);
+		break;
+
+	case DLM_MSG_REMOVE:
+		receive_remove(ls, ms);
+		break;
+
+	/* messages sent from a dir node (remove has no reply) */
+
+	case DLM_MSG_LOOKUP_REPLY:
+		receive_lookup_reply(ls, ms);
+		break;
+
+	default:
+		log_error(ls, "unknown message type %d", ms->m_type);
+	}
+
+	unlock_recovery(ls);
+ out:
+	dlm_put_lockspace(ls);
+	dlm_astd_wake();
+	return 0;
+}
+
+
+/*
+ * Recovery related
+ */
+
+static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	if (middle_conversion(lkb)) {
+		hold_lkb(lkb);
+		ls->ls_stub_ms.m_result = -EINPROGRESS;
+		_remove_from_waiters(lkb);
+		_receive_convert_reply(lkb, &ls->ls_stub_ms);
+
+		/* Same special case as in receive_rcom_lock_args() */
+		lkb->lkb_grmode = DLM_LOCK_IV;
+		rsb_set_flag(lkb->lkb_resource, RSB_RECOVER_CONVERT);
+		unhold_lkb(lkb);
+
+	} else if (lkb->lkb_rqmode >= lkb->lkb_grmode) {
+		lkb->lkb_flags |= DLM_IFL_RESEND;
+	}
+
+	/* lkb->lkb_rqmode < lkb->lkb_grmode shouldn't happen since down
+	   conversions are async; there's no reply from the remote master */
+}
+
+/* A waiting lkb needs recovery if the master node has failed, or
+   the master node is changing (only when no directory is used) */
+
+static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	if (dlm_is_removed(ls, lkb->lkb_nodeid))
+		return 1;
+
+	if (!dlm_no_directory(ls))
+		return 0;
+
+	if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid)
+		return 1;
+
+	return 0;
+}
+
+/* Recovery for locks that are waiting for replies from nodes that are now
+   gone.  We can just complete unlocks and cancels by faking a reply from the
+   dead node.  Requests and up-conversions we flag to be resent after
+   recovery.  Down-conversions can just be completed with a fake reply like
+   unlocks.  Conversions between PR and CW need special attention. */
+
+void dlm_recover_waiters_pre(struct dlm_ls *ls)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+
+	list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
+		log_debug(ls, "pre recover waiter lkid %x type %d flags %x",
+			  lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags);
+
+		/* all outstanding lookups, regardless of destination  will be
+		   resent after recovery is done */
+
+		if (lkb->lkb_wait_type == DLM_MSG_LOOKUP) {
+			lkb->lkb_flags |= DLM_IFL_RESEND;
+			continue;
+		}
+
+		if (!waiter_needs_recovery(ls, lkb))
+			continue;
+
+		switch (lkb->lkb_wait_type) {
+
+		case DLM_MSG_REQUEST:
+			lkb->lkb_flags |= DLM_IFL_RESEND;
+			break;
+
+		case DLM_MSG_CONVERT:
+			recover_convert_waiter(ls, lkb);
+			break;
+
+		case DLM_MSG_UNLOCK:
+			hold_lkb(lkb);
+			ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
+			_remove_from_waiters(lkb);
+			_receive_unlock_reply(lkb, &ls->ls_stub_ms);
+			dlm_put_lkb(lkb);
+			break;
+
+		case DLM_MSG_CANCEL:
+			hold_lkb(lkb);
+			ls->ls_stub_ms.m_result = -DLM_ECANCEL;
+			_remove_from_waiters(lkb);
+			_receive_cancel_reply(lkb, &ls->ls_stub_ms);
+			dlm_put_lkb(lkb);
+			break;
+
+		default:
+			log_error(ls, "invalid lkb wait_type %d",
+				  lkb->lkb_wait_type);
+		}
+		schedule();
+	}
+	mutex_unlock(&ls->ls_waiters_mutex);
+}
+
+static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+{
+	struct dlm_lkb *lkb;
+	int rv = 0;
+
+	mutex_lock(&ls->ls_waiters_mutex);
+	list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+		if (lkb->lkb_flags & DLM_IFL_RESEND) {
+			rv = lkb->lkb_wait_type;
+			_remove_from_waiters(lkb);
+			lkb->lkb_flags &= ~DLM_IFL_RESEND;
+			break;
+		}
+	}
+	mutex_unlock(&ls->ls_waiters_mutex);
+
+	if (!rv)
+		lkb = NULL;
+	*lkb_ret = lkb;
+	return rv;
+}
+
+/* Deal with lookups and lkb's marked RESEND from _pre.  We may now be the
+   master or dir-node for r.  Processing the lkb may result in it being placed
+   back on waiters. */
+
+int dlm_recover_waiters_post(struct dlm_ls *ls)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *r;
+	int error = 0, mstype;
+
+	while (1) {
+		if (dlm_locking_stopped(ls)) {
+			log_debug(ls, "recover_waiters_post aborted");
+			error = -EINTR;
+			break;
+		}
+
+		mstype = remove_resend_waiter(ls, &lkb);
+		if (!mstype)
+			break;
+
+		r = lkb->lkb_resource;
+
+		log_debug(ls, "recover_waiters_post %x type %d flags %x %s",
+			  lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);
+
+		switch (mstype) {
+
+		case DLM_MSG_LOOKUP:
+			hold_rsb(r);
+			lock_rsb(r);
+			_request_lock(r, lkb);
+			if (is_master(r))
+				confirm_master(r, 0);
+			unlock_rsb(r);
+			put_rsb(r);
+			break;
+
+		case DLM_MSG_REQUEST:
+			hold_rsb(r);
+			lock_rsb(r);
+			_request_lock(r, lkb);
+			if (is_master(r))
+				confirm_master(r, 0);
+			unlock_rsb(r);
+			put_rsb(r);
+			break;
+
+		case DLM_MSG_CONVERT:
+			hold_rsb(r);
+			lock_rsb(r);
+			_convert_lock(r, lkb);
+			unlock_rsb(r);
+			put_rsb(r);
+			break;
+
+		default:
+			log_error(ls, "recover_waiters_post type %d", mstype);
+		}
+	}
+
+	return error;
+}
+
+static void purge_queue(struct dlm_rsb *r, struct list_head *queue,
+			int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb))
+{
+	struct dlm_ls *ls = r->res_ls;
+	struct dlm_lkb *lkb, *safe;
+
+	list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
+		if (test(ls, lkb)) {
+			rsb_set_flag(r, RSB_LOCKS_PURGED);
+			del_lkb(r, lkb);
+			/* this put should free the lkb */
+			if (!dlm_put_lkb(lkb))
+				log_error(ls, "purged lkb not released");
+		}
+	}
+}
+
+static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	return (is_master_copy(lkb) && dlm_is_removed(ls, lkb->lkb_nodeid));
+}
+
+static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	return is_master_copy(lkb);
+}
+
+static void purge_dead_locks(struct dlm_rsb *r)
+{
+	purge_queue(r, &r->res_grantqueue, &purge_dead_test);
+	purge_queue(r, &r->res_convertqueue, &purge_dead_test);
+	purge_queue(r, &r->res_waitqueue, &purge_dead_test);
+}
+
+void dlm_purge_mstcpy_locks(struct dlm_rsb *r)
+{
+	purge_queue(r, &r->res_grantqueue, &purge_mstcpy_test);
+	purge_queue(r, &r->res_convertqueue, &purge_mstcpy_test);
+	purge_queue(r, &r->res_waitqueue, &purge_mstcpy_test);
+}
+
+/* Get rid of locks held by nodes that are gone. */
+
+int dlm_purge_locks(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+
+	log_debug(ls, "dlm_purge_locks");
+
+	down_write(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		hold_rsb(r);
+		lock_rsb(r);
+		if (is_master(r))
+			purge_dead_locks(r);
+		unlock_rsb(r);
+		unhold_rsb(r);
+
+		schedule();
+	}
+	up_write(&ls->ls_root_sem);
+
+	return 0;
+}
+
+static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
+{
+	struct dlm_rsb *r, *r_ret = NULL;
+
+	read_lock(&ls->ls_rsbtbl[bucket].lock);
+	list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
+		if (!rsb_flag(r, RSB_LOCKS_PURGED))
+			continue;
+		hold_rsb(r);
+		rsb_clear_flag(r, RSB_LOCKS_PURGED);
+		r_ret = r;
+		break;
+	}
+	read_unlock(&ls->ls_rsbtbl[bucket].lock);
+	return r_ret;
+}
+
+void dlm_grant_after_purge(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int bucket = 0;
+
+	while (1) {
+		r = find_purged_rsb(ls, bucket);
+		if (!r) {
+			if (bucket == ls->ls_rsbtbl_size - 1)
+				break;
+			bucket++;
+			continue;
+		}
+		lock_rsb(r);
+		if (is_master(r)) {
+			grant_pending_locks(r);
+			confirm_master(r, 0);
+		}
+		unlock_rsb(r);
+		put_rsb(r);
+		schedule();
+	}
+}
+
+static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
+					 uint32_t remid)
+{
+	struct dlm_lkb *lkb;
+
+	list_for_each_entry(lkb, head, lkb_statequeue) {
+		if (lkb->lkb_nodeid == nodeid && lkb->lkb_remid == remid)
+			return lkb;
+	}
+	return NULL;
+}
+
+static struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid,
+				    uint32_t remid)
+{
+	struct dlm_lkb *lkb;
+
+	lkb = search_remid_list(&r->res_grantqueue, nodeid, remid);
+	if (lkb)
+		return lkb;
+	lkb = search_remid_list(&r->res_convertqueue, nodeid, remid);
+	if (lkb)
+		return lkb;
+	lkb = search_remid_list(&r->res_waitqueue, nodeid, remid);
+	if (lkb)
+		return lkb;
+	return NULL;
+}
+
+static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+				  struct dlm_rsb *r, struct dlm_rcom *rc)
+{
+	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+	int lvblen;
+
+	lkb->lkb_nodeid = rc->rc_header.h_nodeid;
+	lkb->lkb_ownpid = rl->rl_ownpid;
+	lkb->lkb_remid = rl->rl_lkid;
+	lkb->lkb_exflags = rl->rl_exflags;
+	lkb->lkb_flags = rl->rl_flags & 0x0000FFFF;
+	lkb->lkb_flags |= DLM_IFL_MSTCPY;
+	lkb->lkb_lvbseq = rl->rl_lvbseq;
+	lkb->lkb_rqmode = rl->rl_rqmode;
+	lkb->lkb_grmode = rl->rl_grmode;
+	/* don't set lkb_status because add_lkb wants to itself */
+
+	lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST);
+	lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP);
+
+	if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+		lkb->lkb_lvbptr = allocate_lvb(ls);
+		if (!lkb->lkb_lvbptr)
+			return -ENOMEM;
+		lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) -
+			 sizeof(struct rcom_lock);
+		memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen);
+	}
+
+	/* Conversions between PR and CW (middle modes) need special handling.
+	   The real granted mode of these converting locks cannot be determined
+	   until all locks have been rebuilt on the rsb (recover_conversion) */
+
+	if (rl->rl_wait_type == DLM_MSG_CONVERT && middle_conversion(lkb)) {
+		rl->rl_status = DLM_LKSTS_CONVERT;
+		lkb->lkb_grmode = DLM_LOCK_IV;
+		rsb_set_flag(r, RSB_RECOVER_CONVERT);
+	}
+
+	return 0;
+}
+
+/* This lkb may have been recovered in a previous aborted recovery so we need
+   to check if the rsb already has an lkb with the given remote nodeid/lkid.
+   If so we just send back a standard reply.  If not, we create a new lkb with
+   the given values and send back our lkid.  We send back our lkid by sending
+   back the rcom_lock struct we got but with the remid field filled in. */
+
+int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+	struct dlm_rsb *r;
+	struct dlm_lkb *lkb;
+	int error;
+
+	if (rl->rl_parent_lkid) {
+		error = -EOPNOTSUPP;
+		goto out;
+	}
+
+	error = find_rsb(ls, rl->rl_name, rl->rl_namelen, R_MASTER, &r);
+	if (error)
+		goto out;
+
+	lock_rsb(r);
+
+	lkb = search_remid(r, rc->rc_header.h_nodeid, rl->rl_lkid);
+	if (lkb) {
+		error = -EEXIST;
+		goto out_remid;
+	}
+
+	error = create_lkb(ls, &lkb);
+	if (error)
+		goto out_unlock;
+
+	error = receive_rcom_lock_args(ls, lkb, r, rc);
+	if (error) {
+		__put_lkb(ls, lkb);
+		goto out_unlock;
+	}
+
+	attach_lkb(r, lkb);
+	add_lkb(r, lkb, rl->rl_status);
+	error = 0;
+
+ out_remid:
+	/* this is the new value returned to the lock holder for
+	   saving in its process-copy lkb */
+	rl->rl_remid = lkb->lkb_id;
+
+ out_unlock:
+	unlock_rsb(r);
+	put_rsb(r);
+ out:
+	if (error)
+		log_print("recover_master_copy %d %x", error, rl->rl_lkid);
+	rl->rl_result = error;
+	return error;
+}
+
+int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+	struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+	struct dlm_rsb *r;
+	struct dlm_lkb *lkb;
+	int error;
+
+	error = find_lkb(ls, rl->rl_lkid, &lkb);
+	if (error) {
+		log_error(ls, "recover_process_copy no lkid %x", rl->rl_lkid);
+		return error;
+	}
+
+	DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+	error = rl->rl_result;
+
+	r = lkb->lkb_resource;
+	hold_rsb(r);
+	lock_rsb(r);
+
+	switch (error) {
+	case -EEXIST:
+		log_debug(ls, "master copy exists %x", lkb->lkb_id);
+		/* fall through */
+	case 0:
+		lkb->lkb_remid = rl->rl_remid;
+		break;
+	default:
+		log_error(ls, "dlm_recover_process_copy unknown error %d %x",
+			  error, lkb->lkb_id);
+	}
+
+	/* an ack for dlm_recover_locks() which waits for replies from
+	   all the locks it sends to new masters */
+	dlm_recovered_lock(r);
+
+	unlock_rsb(r);
+	put_rsb(r);
+	dlm_put_lkb(lkb);
+
+	return 0;
+}
+
+int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
+		     int mode, uint32_t flags, void *name, unsigned int namelen,
+		     uint32_t parent_lkid)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	int error;
+
+	lock_recovery(ls);
+
+	error = create_lkb(ls, &lkb);
+	if (error) {
+		kfree(ua);
+		goto out;
+	}
+
+	if (flags & DLM_LKF_VALBLK) {
+		ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+		if (!ua->lksb.sb_lvbptr) {
+			kfree(ua);
+			__put_lkb(ls, lkb);
+			error = -ENOMEM;
+			goto out;
+		}
+	}
+
+	/* After ua is attached to lkb it will be freed by free_lkb().
+	   When DLM_IFL_USER is set, the dlm knows that this is a userspace
+	   lock and that lkb_astparam is the dlm_user_args structure. */
+
+	error = set_lock_args(mode, &ua->lksb, flags, namelen, parent_lkid,
+			      DLM_FAKE_USER_AST, ua, DLM_FAKE_USER_AST, &args);
+	lkb->lkb_flags |= DLM_IFL_USER;
+	ua->old_mode = DLM_LOCK_IV;
+
+	if (error) {
+		__put_lkb(ls, lkb);
+		goto out;
+	}
+
+	error = request_lock(ls, lkb, name, namelen, &args);
+
+	switch (error) {
+	case 0:
+		break;
+	case -EINPROGRESS:
+		error = 0;
+		break;
+	case -EAGAIN:
+		error = 0;
+		/* fall through */
+	default:
+		__put_lkb(ls, lkb);
+		goto out;
+	}
+
+	/* add this new lkb to the per-process list of locks */
+	spin_lock(&ua->proc->locks_spin);
+	kref_get(&lkb->lkb_ref);
+	list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
+	spin_unlock(&ua->proc->locks_spin);
+ out:
+	unlock_recovery(ls);
+	return error;
+}
+
+int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+		     int mode, uint32_t flags, uint32_t lkid, char *lvb_in)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	struct dlm_user_args *ua;
+	int error;
+
+	lock_recovery(ls);
+
+	error = find_lkb(ls, lkid, &lkb);
+	if (error)
+		goto out;
+
+	/* user can change the params on its lock when it converts it, or
+	   add an lvb that didn't exist before */
+
+	ua = (struct dlm_user_args *)lkb->lkb_astparam;
+
+	if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) {
+		ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+		if (!ua->lksb.sb_lvbptr) {
+			error = -ENOMEM;
+			goto out_put;
+		}
+	}
+	if (lvb_in && ua->lksb.sb_lvbptr)
+		memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
+
+	ua->castparam = ua_tmp->castparam;
+	ua->castaddr = ua_tmp->castaddr;
+	ua->bastparam = ua_tmp->bastparam;
+	ua->bastaddr = ua_tmp->bastaddr;
+	ua->user_lksb = ua_tmp->user_lksb;
+	ua->old_mode = lkb->lkb_grmode;
+
+	error = set_lock_args(mode, &ua->lksb, flags, 0, 0, DLM_FAKE_USER_AST,
+			      ua, DLM_FAKE_USER_AST, &args);
+	if (error)
+		goto out_put;
+
+	error = convert_lock(ls, lkb, &args);
+
+	if (error == -EINPROGRESS || error == -EAGAIN)
+		error = 0;
+ out_put:
+	dlm_put_lkb(lkb);
+ out:
+	unlock_recovery(ls);
+	kfree(ua_tmp);
+	return error;
+}
+
+int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+		    uint32_t flags, uint32_t lkid, char *lvb_in)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	struct dlm_user_args *ua;
+	int error;
+
+	lock_recovery(ls);
+
+	error = find_lkb(ls, lkid, &lkb);
+	if (error)
+		goto out;
+
+	ua = (struct dlm_user_args *)lkb->lkb_astparam;
+
+	if (lvb_in && ua->lksb.sb_lvbptr)
+		memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
+	ua->castparam = ua_tmp->castparam;
+	ua->user_lksb = ua_tmp->user_lksb;
+
+	error = set_unlock_args(flags, ua, &args);
+	if (error)
+		goto out_put;
+
+	error = unlock_lock(ls, lkb, &args);
+
+	if (error == -DLM_EUNLOCK)
+		error = 0;
+	if (error)
+		goto out_put;
+
+	spin_lock(&ua->proc->locks_spin);
+	list_del_init(&lkb->lkb_ownqueue);
+	spin_unlock(&ua->proc->locks_spin);
+
+	/* this removes the reference for the proc->locks list added by
+	   dlm_user_request */
+	unhold_lkb(lkb);
+ out_put:
+	dlm_put_lkb(lkb);
+ out:
+	unlock_recovery(ls);
+	return error;
+}
+
+int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+		    uint32_t flags, uint32_t lkid)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_args args;
+	struct dlm_user_args *ua;
+	int error;
+
+	lock_recovery(ls);
+
+	error = find_lkb(ls, lkid, &lkb);
+	if (error)
+		goto out;
+
+	ua = (struct dlm_user_args *)lkb->lkb_astparam;
+	ua->castparam = ua_tmp->castparam;
+	ua->user_lksb = ua_tmp->user_lksb;
+
+	error = set_unlock_args(flags, ua, &args);
+	if (error)
+		goto out_put;
+
+	error = cancel_lock(ls, lkb, &args);
+
+	if (error == -DLM_ECANCEL)
+		error = 0;
+	if (error)
+		goto out_put;
+
+	/* this lkb was removed from the WAITING queue */
+	if (lkb->lkb_grmode == DLM_LOCK_IV) {
+		spin_lock(&ua->proc->locks_spin);
+		list_del_init(&lkb->lkb_ownqueue);
+		spin_unlock(&ua->proc->locks_spin);
+		unhold_lkb(lkb);
+	}
+ out_put:
+	dlm_put_lkb(lkb);
+ out:
+	unlock_recovery(ls);
+	return error;
+}
+
+static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
+
+	if (ua->lksb.sb_lvbptr)
+		kfree(ua->lksb.sb_lvbptr);
+	kfree(ua);
+	lkb->lkb_astparam = (long)NULL;
+
+	/* TODO: propogate to master if needed */
+	return 0;
+}
+
+/* The force flag allows the unlock to go ahead even if the lkb isn't granted.
+   Regardless of what rsb queue the lock is on, it's removed and freed. */
+
+static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+	struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
+	struct dlm_args args;
+	int error;
+
+	/* FIXME: we need to handle the case where the lkb is in limbo
+	   while the rsb is being looked up, currently we assert in
+	   _unlock_lock/is_remote because rsb nodeid is -1. */
+
+	set_unlock_args(DLM_LKF_FORCEUNLOCK, ua, &args);
+
+	error = unlock_lock(ls, lkb, &args);
+	if (error == -DLM_EUNLOCK)
+		error = 0;
+	return error;
+}
+
+/* The ls_clear_proc_locks mutex protects against dlm_user_add_asts() which
+   1) references lkb->ua which we free here and 2) adds lkbs to proc->asts,
+   which we clear here. */
+
+/* proc CLOSING flag is set so no more device_reads should look at proc->asts
+   list, and no more device_writes should add lkb's to proc->locks list; so we
+   shouldn't need to take asts_spin or locks_spin here.  this assumes that
+   device reads/writes/closes are serialized -- FIXME: we may need to serialize
+   them ourself. */
+
+void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
+{
+	struct dlm_lkb *lkb, *safe;
+
+	lock_recovery(ls);
+	mutex_lock(&ls->ls_clear_proc_locks);
+
+	list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) {
+		if (lkb->lkb_ast_type) {
+			list_del(&lkb->lkb_astqueue);
+			unhold_lkb(lkb);
+		}
+
+		list_del_init(&lkb->lkb_ownqueue);
+
+		if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
+			lkb->lkb_flags |= DLM_IFL_ORPHAN;
+			orphan_proc_lock(ls, lkb);
+		} else {
+			lkb->lkb_flags |= DLM_IFL_DEAD;
+			unlock_proc_lock(ls, lkb);
+		}
+
+		/* this removes the reference for the proc->locks list
+		   added by dlm_user_request, it may result in the lkb
+		   being freed */
+
+		dlm_put_lkb(lkb);
+	}
+	mutex_unlock(&ls->ls_clear_proc_locks);
+	unlock_recovery(ls);
+}
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
new file mode 100644
index 0000000..0843a30
--- /dev/null
+++ b/fs/dlm/lock.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOCK_DOT_H__
+#define __LOCK_DOT_H__
+
+void dlm_print_rsb(struct dlm_rsb *r);
+void dlm_dump_rsb(struct dlm_rsb *r);
+void dlm_print_lkb(struct dlm_lkb *lkb);
+int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
+int dlm_modes_compat(int mode1, int mode2);
+int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
+	unsigned int flags, struct dlm_rsb **r_ret);
+void dlm_put_rsb(struct dlm_rsb *r);
+void dlm_hold_rsb(struct dlm_rsb *r);
+int dlm_put_lkb(struct dlm_lkb *lkb);
+void dlm_scan_rsbs(struct dlm_ls *ls);
+
+int dlm_purge_locks(struct dlm_ls *ls);
+void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
+void dlm_grant_after_purge(struct dlm_ls *ls);
+int dlm_recover_waiters_post(struct dlm_ls *ls);
+void dlm_recover_waiters_pre(struct dlm_ls *ls);
+int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
+int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
+
+int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode,
+	uint32_t flags, void *name, unsigned int namelen, uint32_t parent_lkid);
+int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+	int mode, uint32_t flags, uint32_t lkid, char *lvb_in);
+int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+	uint32_t flags, uint32_t lkid, char *lvb_in);
+int dlm_user_cancel(struct dlm_ls *ls,  struct dlm_user_args *ua_tmp,
+	uint32_t flags, uint32_t lkid);
+void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc);
+
+static inline int is_master(struct dlm_rsb *r)
+{
+	return !r->res_nodeid;
+}
+
+static inline void lock_rsb(struct dlm_rsb *r)
+{
+	mutex_lock(&r->res_mutex);
+}
+
+static inline void unlock_rsb(struct dlm_rsb *r)
+{
+	mutex_unlock(&r->res_mutex);
+}
+
+#endif
+
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
new file mode 100644
index 0000000..109333c
--- /dev/null
+++ b/fs/dlm/lockspace.c
@@ -0,0 +1,717 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "recoverd.h"
+#include "ast.h"
+#include "dir.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "memory.h"
+#include "lock.h"
+#include "recover.h"
+
+#ifdef CONFIG_DLM_DEBUG
+int dlm_create_debug_file(struct dlm_ls *ls);
+void dlm_delete_debug_file(struct dlm_ls *ls);
+#else
+static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; }
+static inline void dlm_delete_debug_file(struct dlm_ls *ls) { }
+#endif
+
+static int			ls_count;
+static struct mutex		ls_lock;
+static struct list_head		lslist;
+static spinlock_t		lslist_lock;
+static struct task_struct *	scand_task;
+
+
+static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+	ssize_t ret = len;
+	int n = simple_strtol(buf, NULL, 0);
+
+	switch (n) {
+	case 0:
+		dlm_ls_stop(ls);
+		break;
+	case 1:
+		dlm_ls_start(ls);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+	ls->ls_uevent_result = simple_strtol(buf, NULL, 0);
+	set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags);
+	wake_up(&ls->ls_uevent_wait);
+	return len;
+}
+
+static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u\n", ls->ls_global_id);
+}
+
+static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+	ls->ls_global_id = simple_strtoul(buf, NULL, 0);
+	return len;
+}
+
+static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf)
+{
+	uint32_t status = dlm_recover_status(ls);
+	return snprintf(buf, PAGE_SIZE, "%x\n", status);
+}
+
+static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", ls->ls_recover_nodeid);
+}
+
+struct dlm_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct dlm_ls *, char *);
+	ssize_t (*store)(struct dlm_ls *, const char *, size_t);
+};
+
+static struct dlm_attr dlm_attr_control = {
+	.attr  = {.name = "control", .mode = S_IWUSR},
+	.store = dlm_control_store
+};
+
+static struct dlm_attr dlm_attr_event = {
+	.attr  = {.name = "event_done", .mode = S_IWUSR},
+	.store = dlm_event_store
+};
+
+static struct dlm_attr dlm_attr_id = {
+	.attr  = {.name = "id", .mode = S_IRUGO | S_IWUSR},
+	.show  = dlm_id_show,
+	.store = dlm_id_store
+};
+
+static struct dlm_attr dlm_attr_recover_status = {
+	.attr  = {.name = "recover_status", .mode = S_IRUGO},
+	.show  = dlm_recover_status_show
+};
+
+static struct dlm_attr dlm_attr_recover_nodeid = {
+	.attr  = {.name = "recover_nodeid", .mode = S_IRUGO},
+	.show  = dlm_recover_nodeid_show
+};
+
+static struct attribute *dlm_attrs[] = {
+	&dlm_attr_control.attr,
+	&dlm_attr_event.attr,
+	&dlm_attr_id.attr,
+	&dlm_attr_recover_status.attr,
+	&dlm_attr_recover_nodeid.attr,
+	NULL,
+};
+
+static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr,
+			     char *buf)
+{
+	struct dlm_ls *ls  = container_of(kobj, struct dlm_ls, ls_kobj);
+	struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
+	return a->show ? a->show(ls, buf) : 0;
+}
+
+static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr,
+			      const char *buf, size_t len)
+{
+	struct dlm_ls *ls  = container_of(kobj, struct dlm_ls, ls_kobj);
+	struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
+	return a->store ? a->store(ls, buf, len) : len;
+}
+
+static struct sysfs_ops dlm_attr_ops = {
+	.show  = dlm_attr_show,
+	.store = dlm_attr_store,
+};
+
+static struct kobj_type dlm_ktype = {
+	.default_attrs = dlm_attrs,
+	.sysfs_ops     = &dlm_attr_ops,
+};
+
+static struct kset dlm_kset = {
+	.subsys = &kernel_subsys,
+	.kobj   = {.name = "dlm",},
+	.ktype  = &dlm_ktype,
+};
+
+static int kobject_setup(struct dlm_ls *ls)
+{
+	char lsname[DLM_LOCKSPACE_LEN];
+	int error;
+
+	memset(lsname, 0, DLM_LOCKSPACE_LEN);
+	snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name);
+
+	error = kobject_set_name(&ls->ls_kobj, "%s", lsname);
+	if (error)
+		return error;
+
+	ls->ls_kobj.kset = &dlm_kset;
+	ls->ls_kobj.ktype = &dlm_ktype;
+	return 0;
+}
+
+static int do_uevent(struct dlm_ls *ls, int in)
+{
+	int error;
+
+	if (in)
+		kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE);
+	else
+		kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE);
+
+	error = wait_event_interruptible(ls->ls_uevent_wait,
+			test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags));
+	if (error)
+		goto out;
+
+	error = ls->ls_uevent_result;
+ out:
+	return error;
+}
+
+
+int dlm_lockspace_init(void)
+{
+	int error;
+
+	ls_count = 0;
+	mutex_init(&ls_lock);
+	INIT_LIST_HEAD(&lslist);
+	spin_lock_init(&lslist_lock);
+
+	error = kset_register(&dlm_kset);
+	if (error)
+		printk("dlm_lockspace_init: cannot register kset %d\n", error);
+	return error;
+}
+
+void dlm_lockspace_exit(void)
+{
+	kset_unregister(&dlm_kset);
+}
+
+static int dlm_scand(void *data)
+{
+	struct dlm_ls *ls;
+
+	while (!kthread_should_stop()) {
+		list_for_each_entry(ls, &lslist, ls_list)
+			dlm_scan_rsbs(ls);
+		schedule_timeout_interruptible(dlm_config.scan_secs * HZ);
+	}
+	return 0;
+}
+
+static int dlm_scand_start(void)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	p = kthread_run(dlm_scand, NULL, "dlm_scand");
+	if (IS_ERR(p))
+		error = PTR_ERR(p);
+	else
+		scand_task = p;
+	return error;
+}
+
+static void dlm_scand_stop(void)
+{
+	kthread_stop(scand_task);
+}
+
+static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen)
+{
+	struct dlm_ls *ls;
+
+	spin_lock(&lslist_lock);
+
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (ls->ls_namelen == namelen &&
+		    memcmp(ls->ls_name, name, namelen) == 0)
+			goto out;
+	}
+	ls = NULL;
+ out:
+	spin_unlock(&lslist_lock);
+	return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_global(uint32_t id)
+{
+	struct dlm_ls *ls;
+
+	spin_lock(&lslist_lock);
+
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (ls->ls_global_id == id) {
+			ls->ls_count++;
+			goto out;
+		}
+	}
+	ls = NULL;
+ out:
+	spin_unlock(&lslist_lock);
+	return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace)
+{
+	struct dlm_ls *ls;
+
+	spin_lock(&lslist_lock);
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (ls->ls_local_handle == lockspace) {
+			ls->ls_count++;
+			goto out;
+		}
+	}
+	ls = NULL;
+ out:
+	spin_unlock(&lslist_lock);
+	return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_device(int minor)
+{
+	struct dlm_ls *ls;
+
+	spin_lock(&lslist_lock);
+	list_for_each_entry(ls, &lslist, ls_list) {
+		if (ls->ls_device.minor == minor) {
+			ls->ls_count++;
+			goto out;
+		}
+	}
+	ls = NULL;
+ out:
+	spin_unlock(&lslist_lock);
+	return ls;
+}
+
+void dlm_put_lockspace(struct dlm_ls *ls)
+{
+	spin_lock(&lslist_lock);
+	ls->ls_count--;
+	spin_unlock(&lslist_lock);
+}
+
+static void remove_lockspace(struct dlm_ls *ls)
+{
+	for (;;) {
+		spin_lock(&lslist_lock);
+		if (ls->ls_count == 0) {
+			list_del(&ls->ls_list);
+			spin_unlock(&lslist_lock);
+			return;
+		}
+		spin_unlock(&lslist_lock);
+		ssleep(1);
+	}
+}
+
+static int threads_start(void)
+{
+	int error;
+
+	/* Thread which process lock requests for all lockspace's */
+	error = dlm_astd_start();
+	if (error) {
+		log_print("cannot start dlm_astd thread %d", error);
+		goto fail;
+	}
+
+	error = dlm_scand_start();
+	if (error) {
+		log_print("cannot start dlm_scand thread %d", error);
+		goto astd_fail;
+	}
+
+	/* Thread for sending/receiving messages for all lockspace's */
+	error = dlm_lowcomms_start();
+	if (error) {
+		log_print("cannot start dlm lowcomms %d", error);
+		goto scand_fail;
+	}
+
+	return 0;
+
+ scand_fail:
+	dlm_scand_stop();
+ astd_fail:
+	dlm_astd_stop();
+ fail:
+	return error;
+}
+
+static void threads_stop(void)
+{
+	dlm_scand_stop();
+	dlm_lowcomms_stop();
+	dlm_astd_stop();
+}
+
+static int new_lockspace(char *name, int namelen, void **lockspace,
+			 uint32_t flags, int lvblen)
+{
+	struct dlm_ls *ls;
+	int i, size, error = -ENOMEM;
+
+	if (namelen > DLM_LOCKSPACE_LEN)
+		return -EINVAL;
+
+	if (!lvblen || (lvblen % 8))
+		return -EINVAL;
+
+	if (!try_module_get(THIS_MODULE))
+		return -EINVAL;
+
+	ls = dlm_find_lockspace_name(name, namelen);
+	if (ls) {
+		*lockspace = ls;
+		module_put(THIS_MODULE);
+		return -EEXIST;
+	}
+
+	ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL);
+	if (!ls)
+		goto out;
+	memcpy(ls->ls_name, name, namelen);
+	ls->ls_namelen = namelen;
+	ls->ls_exflags = flags;
+	ls->ls_lvblen = lvblen;
+	ls->ls_count = 0;
+	ls->ls_flags = 0;
+
+	size = dlm_config.rsbtbl_size;
+	ls->ls_rsbtbl_size = size;
+
+	ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);
+	if (!ls->ls_rsbtbl)
+		goto out_lsfree;
+	for (i = 0; i < size; i++) {
+		INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list);
+		INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss);
+		rwlock_init(&ls->ls_rsbtbl[i].lock);
+	}
+
+	size = dlm_config.lkbtbl_size;
+	ls->ls_lkbtbl_size = size;
+
+	ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);
+	if (!ls->ls_lkbtbl)
+		goto out_rsbfree;
+	for (i = 0; i < size; i++) {
+		INIT_LIST_HEAD(&ls->ls_lkbtbl[i].list);
+		rwlock_init(&ls->ls_lkbtbl[i].lock);
+		ls->ls_lkbtbl[i].counter = 1;
+	}
+
+	size = dlm_config.dirtbl_size;
+	ls->ls_dirtbl_size = size;
+
+	ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);
+	if (!ls->ls_dirtbl)
+		goto out_lkbfree;
+	for (i = 0; i < size; i++) {
+		INIT_LIST_HEAD(&ls->ls_dirtbl[i].list);
+		rwlock_init(&ls->ls_dirtbl[i].lock);
+	}
+
+	INIT_LIST_HEAD(&ls->ls_waiters);
+	mutex_init(&ls->ls_waiters_mutex);
+
+	INIT_LIST_HEAD(&ls->ls_nodes);
+	INIT_LIST_HEAD(&ls->ls_nodes_gone);
+	ls->ls_num_nodes = 0;
+	ls->ls_low_nodeid = 0;
+	ls->ls_total_weight = 0;
+	ls->ls_node_array = NULL;
+
+	memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb));
+	ls->ls_stub_rsb.res_ls = ls;
+
+	ls->ls_debug_rsb_dentry = NULL;
+	ls->ls_debug_waiters_dentry = NULL;
+
+	init_waitqueue_head(&ls->ls_uevent_wait);
+	ls->ls_uevent_result = 0;
+
+	ls->ls_recoverd_task = NULL;
+	mutex_init(&ls->ls_recoverd_active);
+	spin_lock_init(&ls->ls_recover_lock);
+	ls->ls_recover_status = 0;
+	ls->ls_recover_seq = 0;
+	ls->ls_recover_args = NULL;
+	init_rwsem(&ls->ls_in_recovery);
+	INIT_LIST_HEAD(&ls->ls_requestqueue);
+	mutex_init(&ls->ls_requestqueue_mutex);
+	mutex_init(&ls->ls_clear_proc_locks);
+
+	ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+	if (!ls->ls_recover_buf)
+		goto out_dirfree;
+
+	INIT_LIST_HEAD(&ls->ls_recover_list);
+	spin_lock_init(&ls->ls_recover_list_lock);
+	ls->ls_recover_list_count = 0;
+	ls->ls_local_handle = ls;
+	init_waitqueue_head(&ls->ls_wait_general);
+	INIT_LIST_HEAD(&ls->ls_root_list);
+	init_rwsem(&ls->ls_root_sem);
+
+	down_write(&ls->ls_in_recovery);
+
+	spin_lock(&lslist_lock);
+	list_add(&ls->ls_list, &lslist);
+	spin_unlock(&lslist_lock);
+
+	/* needs to find ls in lslist */
+	error = dlm_recoverd_start(ls);
+	if (error) {
+		log_error(ls, "can't start dlm_recoverd %d", error);
+		goto out_rcomfree;
+	}
+
+	dlm_create_debug_file(ls);
+
+	error = kobject_setup(ls);
+	if (error)
+		goto out_del;
+
+	error = kobject_register(&ls->ls_kobj);
+	if (error)
+		goto out_del;
+
+	error = do_uevent(ls, 1);
+	if (error)
+		goto out_unreg;
+
+	*lockspace = ls;
+	return 0;
+
+ out_unreg:
+	kobject_unregister(&ls->ls_kobj);
+ out_del:
+	dlm_delete_debug_file(ls);
+	dlm_recoverd_stop(ls);
+ out_rcomfree:
+	spin_lock(&lslist_lock);
+	list_del(&ls->ls_list);
+	spin_unlock(&lslist_lock);
+	kfree(ls->ls_recover_buf);
+ out_dirfree:
+	kfree(ls->ls_dirtbl);
+ out_lkbfree:
+	kfree(ls->ls_lkbtbl);
+ out_rsbfree:
+	kfree(ls->ls_rsbtbl);
+ out_lsfree:
+	kfree(ls);
+ out:
+	module_put(THIS_MODULE);
+	return error;
+}
+
+int dlm_new_lockspace(char *name, int namelen, void **lockspace,
+		      uint32_t flags, int lvblen)
+{
+	int error = 0;
+
+	mutex_lock(&ls_lock);
+	if (!ls_count)
+		error = threads_start();
+	if (error)
+		goto out;
+
+	error = new_lockspace(name, namelen, lockspace, flags, lvblen);
+	if (!error)
+		ls_count++;
+ out:
+	mutex_unlock(&ls_lock);
+	return error;
+}
+
+/* Return 1 if the lockspace still has active remote locks,
+ *        2 if the lockspace still has active local locks.
+ */
+static int lockspace_busy(struct dlm_ls *ls)
+{
+	int i, lkb_found = 0;
+	struct dlm_lkb *lkb;
+
+	/* NOTE: We check the lockidtbl here rather than the resource table.
+	   This is because there may be LKBs queued as ASTs that have been
+	   unlinked from their RSBs and are pending deletion once the AST has
+	   been delivered */
+
+	for (i = 0; i < ls->ls_lkbtbl_size; i++) {
+		read_lock(&ls->ls_lkbtbl[i].lock);
+		if (!list_empty(&ls->ls_lkbtbl[i].list)) {
+			lkb_found = 1;
+			list_for_each_entry(lkb, &ls->ls_lkbtbl[i].list,
+					    lkb_idtbl_list) {
+				if (!lkb->lkb_nodeid) {
+					read_unlock(&ls->ls_lkbtbl[i].lock);
+					return 2;
+				}
+			}
+		}
+		read_unlock(&ls->ls_lkbtbl[i].lock);
+	}
+	return lkb_found;
+}
+
+static int release_lockspace(struct dlm_ls *ls, int force)
+{
+	struct dlm_lkb *lkb;
+	struct dlm_rsb *rsb;
+	struct list_head *head;
+	int i;
+	int busy = lockspace_busy(ls);
+
+	if (busy > force)
+		return -EBUSY;
+
+	if (force < 3)
+		do_uevent(ls, 0);
+
+	dlm_recoverd_stop(ls);
+
+	remove_lockspace(ls);
+
+	dlm_delete_debug_file(ls);
+
+	dlm_astd_suspend();
+
+	kfree(ls->ls_recover_buf);
+
+	/*
+	 * Free direntry structs.
+	 */
+
+	dlm_dir_clear(ls);
+	kfree(ls->ls_dirtbl);
+
+	/*
+	 * Free all lkb's on lkbtbl[] lists.
+	 */
+
+	for (i = 0; i < ls->ls_lkbtbl_size; i++) {
+		head = &ls->ls_lkbtbl[i].list;
+		while (!list_empty(head)) {
+			lkb = list_entry(head->next, struct dlm_lkb,
+					 lkb_idtbl_list);
+
+			list_del(&lkb->lkb_idtbl_list);
+
+			dlm_del_ast(lkb);
+
+			if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY)
+				free_lvb(lkb->lkb_lvbptr);
+
+			free_lkb(lkb);
+		}
+	}
+	dlm_astd_resume();
+
+	kfree(ls->ls_lkbtbl);
+
+	/*
+	 * Free all rsb's on rsbtbl[] lists
+	 */
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		head = &ls->ls_rsbtbl[i].list;
+		while (!list_empty(head)) {
+			rsb = list_entry(head->next, struct dlm_rsb,
+					 res_hashchain);
+
+			list_del(&rsb->res_hashchain);
+			free_rsb(rsb);
+		}
+
+		head = &ls->ls_rsbtbl[i].toss;
+		while (!list_empty(head)) {
+			rsb = list_entry(head->next, struct dlm_rsb,
+					 res_hashchain);
+			list_del(&rsb->res_hashchain);
+			free_rsb(rsb);
+		}
+	}
+
+	kfree(ls->ls_rsbtbl);
+
+	/*
+	 * Free structures on any other lists
+	 */
+
+	kfree(ls->ls_recover_args);
+	dlm_clear_free_entries(ls);
+	dlm_clear_members(ls);
+	dlm_clear_members_gone(ls);
+	kfree(ls->ls_node_array);
+	kobject_unregister(&ls->ls_kobj);
+	kfree(ls);
+
+	mutex_lock(&ls_lock);
+	ls_count--;
+	if (!ls_count)
+		threads_stop();
+	mutex_unlock(&ls_lock);
+
+	module_put(THIS_MODULE);
+	return 0;
+}
+
+/*
+ * Called when a system has released all its locks and is not going to use the
+ * lockspace any longer.  We free everything we're managing for this lockspace.
+ * Remaining nodes will go through the recovery process as if we'd died.  The
+ * lockspace must continue to function as usual, participating in recoveries,
+ * until this returns.
+ *
+ * Force has 4 possible values:
+ * 0 - don't destroy locksapce if it has any LKBs
+ * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs
+ * 2 - destroy lockspace regardless of LKBs
+ * 3 - destroy lockspace as part of a forced shutdown
+ */
+
+int dlm_release_lockspace(void *lockspace, int force)
+{
+	struct dlm_ls *ls;
+
+	ls = dlm_find_lockspace_local(lockspace);
+	if (!ls)
+		return -EINVAL;
+	dlm_put_lockspace(ls);
+	return release_lockspace(ls, force);
+}
+
diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h
new file mode 100644
index 0000000..891eabb
--- /dev/null
+++ b/fs/dlm/lockspace.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOCKSPACE_DOT_H__
+#define __LOCKSPACE_DOT_H__
+
+int dlm_lockspace_init(void);
+void dlm_lockspace_exit(void);
+struct dlm_ls *dlm_find_lockspace_global(uint32_t id);
+struct dlm_ls *dlm_find_lockspace_local(void *id);
+struct dlm_ls *dlm_find_lockspace_device(int minor);
+void dlm_put_lockspace(struct dlm_ls *ls);
+
+#endif				/* __LOCKSPACE_DOT_H__ */
+
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
new file mode 100644
index 0000000..23f5ce1
--- /dev/null
+++ b/fs/dlm/lowcomms.c
@@ -0,0 +1,1238 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * lowcomms.c
+ *
+ * This is the "low-level" comms layer.
+ *
+ * It is responsible for sending/receiving messages
+ * from other nodes in the cluster.
+ *
+ * Cluster nodes are referred to by their nodeids. nodeids are
+ * simply 32 bit numbers to the locking module - if they need to
+ * be expanded for the cluster infrastructure then that is it's
+ * responsibility. It is this layer's
+ * responsibility to resolve these into IP address or
+ * whatever it needs for inter-node communication.
+ *
+ * The comms level is two kernel threads that deal mainly with
+ * the receiving of messages from other nodes and passing them
+ * up to the mid-level comms layer (which understands the
+ * message format) for execution by the locking core, and
+ * a send thread which does all the setting up of connections
+ * to remote nodes and the sending of data. Threads are not allowed
+ * to send their own data because it may cause them to wait in times
+ * of high load. Also, this way, the sending thread can collect together
+ * messages bound for one node and send them in one block.
+ *
+ * I don't see any problem with the recv thread executing the locking
+ * code on behalf of remote processes as the locking code is
+ * short, efficient and never (well, hardly ever) waits.
+ *
+ */
+
+#include <asm/ioctls.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/sctp/user.h>
+#include <linux/pagemap.h>
+#include <linux/socket.h>
+#include <linux/idr.h>
+
+#include "dlm_internal.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "midcomms.h"
+
+static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
+static int			dlm_local_count;
+static int			dlm_local_nodeid;
+
+/* One of these per connected node */
+
+#define NI_INIT_PENDING 1
+#define NI_WRITE_PENDING 2
+
+struct nodeinfo {
+	spinlock_t		lock;
+	sctp_assoc_t		assoc_id;
+	unsigned long		flags;
+	struct list_head	write_list; /* nodes with pending writes */
+	struct list_head	writequeue; /* outgoing writequeue_entries */
+	spinlock_t		writequeue_lock;
+	int			nodeid;
+};
+
+static DEFINE_IDR(nodeinfo_idr);
+static struct rw_semaphore	nodeinfo_lock;
+static int			max_nodeid;
+
+struct cbuf {
+	unsigned		base;
+	unsigned		len;
+	unsigned		mask;
+};
+
+/* Just the one of these, now. But this struct keeps
+   the connection-specific variables together */
+
+#define CF_READ_PENDING 1
+
+struct connection {
+	struct socket          *sock;
+	unsigned long		flags;
+	struct page            *rx_page;
+	atomic_t		waiting_requests;
+	struct cbuf		cb;
+	int                     eagain_flag;
+};
+
+/* An entry waiting to be sent */
+
+struct writequeue_entry {
+	struct list_head	list;
+	struct page            *page;
+	int			offset;
+	int			len;
+	int			end;
+	int			users;
+	struct nodeinfo        *ni;
+};
+
+#define CBUF_ADD(cb, n) do { (cb)->len += n; } while(0)
+#define CBUF_EMPTY(cb) ((cb)->len == 0)
+#define CBUF_MAY_ADD(cb, n) (((cb)->len + (n)) < ((cb)->mask + 1))
+#define CBUF_DATA(cb) (((cb)->base + (cb)->len) & (cb)->mask)
+
+#define CBUF_INIT(cb, size) \
+do { \
+	(cb)->base = (cb)->len = 0; \
+	(cb)->mask = ((size)-1); \
+} while(0)
+
+#define CBUF_EAT(cb, n) \
+do { \
+	(cb)->len  -= (n); \
+	(cb)->base += (n); \
+	(cb)->base &= (cb)->mask; \
+} while(0)
+
+
+/* List of nodes which have writes pending */
+static struct list_head write_nodes;
+static spinlock_t write_nodes_lock;
+
+/* Maximum number of incoming messages to process before
+ * doing a schedule()
+ */
+#define MAX_RX_MSG_COUNT 25
+
+/* Manage daemons */
+static struct task_struct *recv_task;
+static struct task_struct *send_task;
+static wait_queue_head_t lowcomms_recv_wait;
+static atomic_t accepting;
+
+/* The SCTP connection */
+static struct connection sctp_con;
+
+
+static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
+{
+	struct sockaddr_storage addr;
+	int error;
+
+	if (!dlm_local_count)
+		return -1;
+
+	error = dlm_nodeid_to_addr(nodeid, &addr);
+	if (error)
+		return error;
+
+	if (dlm_local_addr[0]->ss_family == AF_INET) {
+	        struct sockaddr_in *in4  = (struct sockaddr_in *) &addr;
+		struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
+		ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
+	} else {
+	        struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &addr;
+		struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
+		memcpy(&ret6->sin6_addr, &in6->sin6_addr,
+		       sizeof(in6->sin6_addr));
+	}
+
+	return 0;
+}
+
+static struct nodeinfo *nodeid2nodeinfo(int nodeid, int alloc)
+{
+	struct nodeinfo *ni;
+	int r;
+	int n;
+
+	down_read(&nodeinfo_lock);
+	ni = idr_find(&nodeinfo_idr, nodeid);
+	up_read(&nodeinfo_lock);
+
+	if (!ni && alloc) {
+		down_write(&nodeinfo_lock);
+
+		ni = idr_find(&nodeinfo_idr, nodeid);
+		if (ni)
+			goto out_up;
+
+		r = idr_pre_get(&nodeinfo_idr, alloc);
+		if (!r)
+			goto out_up;
+
+		ni = kmalloc(sizeof(struct nodeinfo), alloc);
+		if (!ni)
+			goto out_up;
+
+		r = idr_get_new_above(&nodeinfo_idr, ni, nodeid, &n);
+		if (r) {
+			kfree(ni);
+			ni = NULL;
+			goto out_up;
+		}
+		if (n != nodeid) {
+			idr_remove(&nodeinfo_idr, n);
+			kfree(ni);
+			ni = NULL;
+			goto out_up;
+		}
+		memset(ni, 0, sizeof(struct nodeinfo));
+		spin_lock_init(&ni->lock);
+		INIT_LIST_HEAD(&ni->writequeue);
+		spin_lock_init(&ni->writequeue_lock);
+		ni->nodeid = nodeid;
+
+		if (nodeid > max_nodeid)
+			max_nodeid = nodeid;
+	out_up:
+		up_write(&nodeinfo_lock);
+	}
+
+	return ni;
+}
+
+/* Don't call this too often... */
+static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc)
+{
+	int i;
+	struct nodeinfo *ni;
+
+	for (i=1; i<=max_nodeid; i++) {
+		ni = nodeid2nodeinfo(i, 0);
+		if (ni && ni->assoc_id == assoc)
+			return ni;
+	}
+	return NULL;
+}
+
+/* Data or notification available on socket */
+static void lowcomms_data_ready(struct sock *sk, int count_unused)
+{
+	atomic_inc(&sctp_con.waiting_requests);
+	if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
+		return;
+
+	wake_up_interruptible(&lowcomms_recv_wait);
+}
+
+
+/* Add the port number to an IP6 or 4 sockaddr and return the address length.
+   Also padd out the struct with zeros to make comparisons meaningful */
+
+static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
+			  int *addr_len)
+{
+	struct sockaddr_in *local4_addr;
+	struct sockaddr_in6 *local6_addr;
+
+	if (!dlm_local_count)
+		return;
+
+	if (!port) {
+		if (dlm_local_addr[0]->ss_family == AF_INET) {
+			local4_addr = (struct sockaddr_in *)dlm_local_addr[0];
+			port = be16_to_cpu(local4_addr->sin_port);
+		} else {
+			local6_addr = (struct sockaddr_in6 *)dlm_local_addr[0];
+			port = be16_to_cpu(local6_addr->sin6_port);
+		}
+	}
+
+	saddr->ss_family = dlm_local_addr[0]->ss_family;
+	if (dlm_local_addr[0]->ss_family == AF_INET) {
+		struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
+		in4_addr->sin_port = cpu_to_be16(port);
+		memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
+		memset(in4_addr+1, 0, sizeof(struct sockaddr_storage) -
+				      sizeof(struct sockaddr_in));
+		*addr_len = sizeof(struct sockaddr_in);
+	} else {
+		struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
+		in6_addr->sin6_port = cpu_to_be16(port);
+		memset(in6_addr+1, 0, sizeof(struct sockaddr_storage) -
+				      sizeof(struct sockaddr_in6));
+		*addr_len = sizeof(struct sockaddr_in6);
+	}
+}
+
+/* Close the connection and tidy up */
+static void close_connection(void)
+{
+	if (sctp_con.sock) {
+		sock_release(sctp_con.sock);
+		sctp_con.sock = NULL;
+	}
+
+	if (sctp_con.rx_page) {
+		__free_page(sctp_con.rx_page);
+		sctp_con.rx_page = NULL;
+	}
+}
+
+/* We only send shutdown messages to nodes that are not part of the cluster */
+static void send_shutdown(sctp_assoc_t associd)
+{
+	static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct msghdr outmessage;
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+	int ret;
+
+	outmessage.msg_name = NULL;
+	outmessage.msg_namelen = 0;
+	outmessage.msg_control = outcmsg;
+	outmessage.msg_controllen = sizeof(outcmsg);
+	outmessage.msg_flags = MSG_EOR;
+
+	cmsg = CMSG_FIRSTHDR(&outmessage);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+	outmessage.msg_controllen = cmsg->cmsg_len;
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+	sinfo->sinfo_flags |= MSG_EOF;
+	sinfo->sinfo_assoc_id = associd;
+
+	ret = kernel_sendmsg(sctp_con.sock, &outmessage, NULL, 0, 0);
+
+	if (ret != 0)
+		log_print("send EOF to node failed: %d", ret);
+}
+
+
+/* INIT failed but we don't know which node...
+   restart INIT on all pending nodes */
+static void init_failed(void)
+{
+	int i;
+	struct nodeinfo *ni;
+
+	for (i=1; i<=max_nodeid; i++) {
+		ni = nodeid2nodeinfo(i, 0);
+		if (!ni)
+			continue;
+
+		if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
+			ni->assoc_id = 0;
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+		}
+	}
+	wake_up_process(send_task);
+}
+
+/* Something happened to an association */
+static void process_sctp_notification(struct msghdr *msg, char *buf)
+{
+	union sctp_notification *sn = (union sctp_notification *)buf;
+
+	if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) {
+		switch (sn->sn_assoc_change.sac_state) {
+
+		case SCTP_COMM_UP:
+		case SCTP_RESTART:
+		{
+			/* Check that the new node is in the lockspace */
+			struct sctp_prim prim;
+			mm_segment_t fs;
+			int nodeid;
+			int prim_len, ret;
+			int addr_len;
+			struct nodeinfo *ni;
+
+			/* This seems to happen when we received a connection
+			 * too early... or something...  anyway, it happens but
+			 * we always seem to get a real message too, see
+			 * receive_from_sock */
+
+			if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) {
+				log_print("COMM_UP for invalid assoc ID %d",
+					 (int)sn->sn_assoc_change.sac_assoc_id);
+				init_failed();
+				return;
+			}
+			memset(&prim, 0, sizeof(struct sctp_prim));
+			prim_len = sizeof(struct sctp_prim);
+			prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id;
+
+			fs = get_fs();
+			set_fs(get_ds());
+			ret = sctp_con.sock->ops->getsockopt(sctp_con.sock,
+						IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
+						(char*)&prim, &prim_len);
+			set_fs(fs);
+			if (ret < 0) {
+				struct nodeinfo *ni;
+
+				log_print("getsockopt/sctp_primary_addr on "
+					  "new assoc %d failed : %d",
+				    (int)sn->sn_assoc_change.sac_assoc_id, ret);
+
+				/* Retry INIT later */
+				ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
+				if (ni)
+					clear_bit(NI_INIT_PENDING, &ni->flags);
+				return;
+			}
+			make_sockaddr(&prim.ssp_addr, 0, &addr_len);
+			if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
+				log_print("reject connect from unknown addr");
+				send_shutdown(prim.ssp_assoc_id);
+				return;
+			}
+
+			ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
+			if (!ni)
+				return;
+
+			/* Save the assoc ID */
+			spin_lock(&ni->lock);
+			ni->assoc_id = sn->sn_assoc_change.sac_assoc_id;
+			spin_unlock(&ni->lock);
+
+			log_print("got new/restarted association %d nodeid %d",
+			       (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
+
+			/* Send any pending writes */
+			clear_bit(NI_INIT_PENDING, &ni->flags);
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+			wake_up_process(send_task);
+		}
+		break;
+
+		case SCTP_COMM_LOST:
+		case SCTP_SHUTDOWN_COMP:
+		{
+			struct nodeinfo *ni;
+
+			ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
+			if (ni) {
+				spin_lock(&ni->lock);
+				ni->assoc_id = 0;
+				spin_unlock(&ni->lock);
+			}
+		}
+		break;
+
+		/* We don't know which INIT failed, so clear the PENDING flags
+		 * on them all.  if assoc_id is zero then it will then try
+		 * again */
+
+		case SCTP_CANT_STR_ASSOC:
+		{
+			log_print("Can't start SCTP association - retrying");
+			init_failed();
+		}
+		break;
+
+		default:
+			log_print("unexpected SCTP assoc change id=%d state=%d",
+				  (int)sn->sn_assoc_change.sac_assoc_id,
+				  sn->sn_assoc_change.sac_state);
+		}
+	}
+}
+
+/* Data received from remote end */
+static int receive_from_sock(void)
+{
+	int ret = 0;
+	struct msghdr msg;
+	struct kvec iov[2];
+	unsigned len;
+	int r;
+	struct sctp_sndrcvinfo *sinfo;
+	struct cmsghdr *cmsg;
+	struct nodeinfo *ni;
+
+	/* These two are marginally too big for stack allocation, but this
+	 * function is (currently) only called by dlm_recvd so static should be
+	 * OK.
+	 */
+	static struct sockaddr_storage msgname;
+	static char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+
+	if (sctp_con.sock == NULL)
+		goto out;
+
+	if (sctp_con.rx_page == NULL) {
+		/*
+		 * This doesn't need to be atomic, but I think it should
+		 * improve performance if it is.
+		 */
+		sctp_con.rx_page = alloc_page(GFP_ATOMIC);
+		if (sctp_con.rx_page == NULL)
+			goto out_resched;
+		CBUF_INIT(&sctp_con.cb, PAGE_CACHE_SIZE);
+	}
+
+	memset(&incmsg, 0, sizeof(incmsg));
+	memset(&msgname, 0, sizeof(msgname));
+
+	memset(incmsg, 0, sizeof(incmsg));
+	msg.msg_name = &msgname;
+	msg.msg_namelen = sizeof(msgname);
+	msg.msg_flags = 0;
+	msg.msg_control = incmsg;
+	msg.msg_controllen = sizeof(incmsg);
+
+	/* I don't see why this circular buffer stuff is necessary for SCTP
+	 * which is a packet-based protocol, but the whole thing breaks under
+	 * load without it! The overhead is minimal (and is in the TCP lowcomms
+	 * anyway, of course) so I'll leave it in until I can figure out what's
+	 * really happening.
+	 */
+
+	/*
+	 * iov[0] is the bit of the circular buffer between the current end
+	 * point (cb.base + cb.len) and the end of the buffer.
+	 */
+	iov[0].iov_len = sctp_con.cb.base - CBUF_DATA(&sctp_con.cb);
+	iov[0].iov_base = page_address(sctp_con.rx_page) +
+			  CBUF_DATA(&sctp_con.cb);
+	iov[1].iov_len = 0;
+
+	/*
+	 * iov[1] is the bit of the circular buffer between the start of the
+	 * buffer and the start of the currently used section (cb.base)
+	 */
+	if (CBUF_DATA(&sctp_con.cb) >= sctp_con.cb.base) {
+		iov[0].iov_len = PAGE_CACHE_SIZE - CBUF_DATA(&sctp_con.cb);
+		iov[1].iov_len = sctp_con.cb.base;
+		iov[1].iov_base = page_address(sctp_con.rx_page);
+		msg.msg_iovlen = 2;
+	}
+	len = iov[0].iov_len + iov[1].iov_len;
+
+	r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, 1, len,
+				 MSG_NOSIGNAL | MSG_DONTWAIT);
+	if (ret <= 0)
+		goto out_close;
+
+	msg.msg_control = incmsg;
+	msg.msg_controllen = sizeof(incmsg);
+	cmsg = CMSG_FIRSTHDR(&msg);
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+
+	if (msg.msg_flags & MSG_NOTIFICATION) {
+		process_sctp_notification(&msg, page_address(sctp_con.rx_page));
+		return 0;
+	}
+
+	/* Is this a new association ? */
+	ni = nodeid2nodeinfo(le32_to_cpu(sinfo->sinfo_ppid), GFP_KERNEL);
+	if (ni) {
+		ni->assoc_id = sinfo->sinfo_assoc_id;
+		if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
+
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+			wake_up_process(send_task);
+		}
+	}
+
+	/* INIT sends a message with length of 1 - ignore it */
+	if (r == 1)
+		return 0;
+
+	CBUF_ADD(&sctp_con.cb, ret);
+	ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid),
+					  page_address(sctp_con.rx_page),
+					  sctp_con.cb.base, sctp_con.cb.len,
+					  PAGE_CACHE_SIZE);
+	if (ret < 0)
+		goto out_close;
+	CBUF_EAT(&sctp_con.cb, ret);
+
+      out:
+	ret = 0;
+	goto out_ret;
+
+      out_resched:
+	lowcomms_data_ready(sctp_con.sock->sk, 0);
+	ret = 0;
+	schedule();
+	goto out_ret;
+
+      out_close:
+	if (ret != -EAGAIN)
+		log_print("error reading from sctp socket: %d", ret);
+      out_ret:
+	return ret;
+}
+
+/* Bind to an IP address. SCTP allows multiple address so it can do multi-homing */
+static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num)
+{
+	mm_segment_t fs;
+	int result = 0;
+
+	fs = get_fs();
+	set_fs(get_ds());
+	if (num == 1)
+		result = sctp_con.sock->ops->bind(sctp_con.sock,
+					(struct sockaddr *) addr, addr_len);
+	else
+		result = sctp_con.sock->ops->setsockopt(sctp_con.sock, SOL_SCTP,
+				SCTP_SOCKOPT_BINDX_ADD, (char *)addr, addr_len);
+	set_fs(fs);
+
+	if (result < 0)
+		log_print("Can't bind to port %d addr number %d",
+			  dlm_config.tcp_port, num);
+
+	return result;
+}
+
+static void init_local(void)
+{
+	struct sockaddr_storage sas, *addr;
+	int i;
+
+	dlm_local_nodeid = dlm_our_nodeid();
+
+	for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
+		if (dlm_our_addr(&sas, i))
+			break;
+
+		addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+		if (!addr)
+			break;
+		memcpy(addr, &sas, sizeof(*addr));
+		dlm_local_addr[dlm_local_count++] = addr;
+	}
+}
+
+/* Initialise SCTP socket and bind to all interfaces */
+static int init_sock(void)
+{
+	mm_segment_t fs;
+	struct socket *sock = NULL;
+	struct sockaddr_storage localaddr;
+	struct sctp_event_subscribe subscribe;
+	int result = -EINVAL, num = 1, i, addr_len;
+
+	if (!dlm_local_count) {
+		init_local();
+		if (!dlm_local_count) {
+			log_print("no local IP address has been set");
+			goto out;
+		}
+	}
+
+	result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET,
+				  IPPROTO_SCTP, &sock);
+	if (result < 0) {
+		log_print("Can't create comms socket, check SCTP is loaded");
+		goto out;
+	}
+
+	/* Listen for events */
+	memset(&subscribe, 0, sizeof(subscribe));
+	subscribe.sctp_data_io_event = 1;
+	subscribe.sctp_association_event = 1;
+	subscribe.sctp_send_failure_event = 1;
+	subscribe.sctp_shutdown_event = 1;
+	subscribe.sctp_partial_delivery_event = 1;
+
+	fs = get_fs();
+	set_fs(get_ds());
+	result = sock->ops->setsockopt(sock, SOL_SCTP, SCTP_EVENTS,
+				       (char *)&subscribe, sizeof(subscribe));
+	set_fs(fs);
+
+	if (result < 0) {
+		log_print("Failed to set SCTP_EVENTS on socket: result=%d",
+			  result);
+		goto create_delsock;
+	}
+
+	/* Init con struct */
+	sock->sk->sk_user_data = &sctp_con;
+	sctp_con.sock = sock;
+	sctp_con.sock->sk->sk_data_ready = lowcomms_data_ready;
+
+	/* Bind to all interfaces. */
+	for (i = 0; i < dlm_local_count; i++) {
+		memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
+		make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len);
+
+		result = add_bind_addr(&localaddr, addr_len, num);
+		if (result)
+			goto create_delsock;
+		++num;
+	}
+
+	result = sock->ops->listen(sock, 5);
+	if (result < 0) {
+		log_print("Can't set socket listening");
+		goto create_delsock;
+	}
+
+	return 0;
+
+ create_delsock:
+	sock_release(sock);
+	sctp_con.sock = NULL;
+ out:
+	return result;
+}
+
+
+static struct writequeue_entry *new_writequeue_entry(int allocation)
+{
+	struct writequeue_entry *entry;
+
+	entry = kmalloc(sizeof(struct writequeue_entry), allocation);
+	if (!entry)
+		return NULL;
+
+	entry->page = alloc_page(allocation);
+	if (!entry->page) {
+		kfree(entry);
+		return NULL;
+	}
+
+	entry->offset = 0;
+	entry->len = 0;
+	entry->end = 0;
+	entry->users = 0;
+
+	return entry;
+}
+
+void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc)
+{
+	struct writequeue_entry *e;
+	int offset = 0;
+	int users = 0;
+	struct nodeinfo *ni;
+
+	if (!atomic_read(&accepting))
+		return NULL;
+
+	ni = nodeid2nodeinfo(nodeid, allocation);
+	if (!ni)
+		return NULL;
+
+	spin_lock(&ni->writequeue_lock);
+	e = list_entry(ni->writequeue.prev, struct writequeue_entry, list);
+	if (((struct list_head *) e == &ni->writequeue) ||
+	    (PAGE_CACHE_SIZE - e->end < len)) {
+		e = NULL;
+	} else {
+		offset = e->end;
+		e->end += len;
+		users = e->users++;
+	}
+	spin_unlock(&ni->writequeue_lock);
+
+	if (e) {
+	      got_one:
+		if (users == 0)
+			kmap(e->page);
+		*ppc = page_address(e->page) + offset;
+		return e;
+	}
+
+	e = new_writequeue_entry(allocation);
+	if (e) {
+		spin_lock(&ni->writequeue_lock);
+		offset = e->end;
+		e->end += len;
+		e->ni = ni;
+		users = e->users++;
+		list_add_tail(&e->list, &ni->writequeue);
+		spin_unlock(&ni->writequeue_lock);
+		goto got_one;
+	}
+	return NULL;
+}
+
+void dlm_lowcomms_commit_buffer(void *arg)
+{
+	struct writequeue_entry *e = (struct writequeue_entry *) arg;
+	int users;
+	struct nodeinfo *ni = e->ni;
+
+	if (!atomic_read(&accepting))
+		return;
+
+	spin_lock(&ni->writequeue_lock);
+	users = --e->users;
+	if (users)
+		goto out;
+	e->len = e->end - e->offset;
+	kunmap(e->page);
+	spin_unlock(&ni->writequeue_lock);
+
+	if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+		spin_lock_bh(&write_nodes_lock);
+		list_add_tail(&ni->write_list, &write_nodes);
+		spin_unlock_bh(&write_nodes_lock);
+		wake_up_process(send_task);
+	}
+	return;
+
+      out:
+	spin_unlock(&ni->writequeue_lock);
+	return;
+}
+
+static void free_entry(struct writequeue_entry *e)
+{
+	__free_page(e->page);
+	kfree(e);
+}
+
+/* Initiate an SCTP association. In theory we could just use sendmsg() on
+   the first IP address and it should work, but this allows us to set up the
+   association before sending any valuable data that we can't afford to lose.
+   It also keeps the send path clean as it can now always use the association ID */
+static void initiate_association(int nodeid)
+{
+	struct sockaddr_storage rem_addr;
+	static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct msghdr outmessage;
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+	int ret;
+	int addrlen;
+	char buf[1];
+	struct kvec iov[1];
+	struct nodeinfo *ni;
+
+	log_print("Initiating association with node %d", nodeid);
+
+	ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
+	if (!ni)
+		return;
+
+	if (nodeid_to_addr(nodeid, (struct sockaddr *)&rem_addr)) {
+		log_print("no address for nodeid %d", nodeid);
+		return;
+	}
+
+	make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen);
+
+	outmessage.msg_name = &rem_addr;
+	outmessage.msg_namelen = addrlen;
+	outmessage.msg_control = outcmsg;
+	outmessage.msg_controllen = sizeof(outcmsg);
+	outmessage.msg_flags = MSG_EOR;
+
+	iov[0].iov_base = buf;
+	iov[0].iov_len = 1;
+
+	/* Real INIT messages seem to cause trouble. Just send a 1 byte message
+	   we can afford to lose */
+	cmsg = CMSG_FIRSTHDR(&outmessage);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+	sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
+
+	outmessage.msg_controllen = cmsg->cmsg_len;
+	ret = kernel_sendmsg(sctp_con.sock, &outmessage, iov, 1, 1);
+	if (ret < 0) {
+		log_print("send INIT to node failed: %d", ret);
+		/* Try again later */
+		clear_bit(NI_INIT_PENDING, &ni->flags);
+	}
+}
+
+/* Send a message */
+static int send_to_sock(struct nodeinfo *ni)
+{
+	int ret = 0;
+	struct writequeue_entry *e;
+	int len, offset;
+	struct msghdr outmsg;
+	static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+	struct cmsghdr *cmsg;
+	struct sctp_sndrcvinfo *sinfo;
+	struct kvec iov;
+
+        /* See if we need to init an association before we start
+	   sending precious messages */
+	spin_lock(&ni->lock);
+	if (!ni->assoc_id && !test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
+		spin_unlock(&ni->lock);
+		initiate_association(ni->nodeid);
+		return 0;
+	}
+	spin_unlock(&ni->lock);
+
+	outmsg.msg_name = NULL; /* We use assoc_id */
+	outmsg.msg_namelen = 0;
+	outmsg.msg_control = outcmsg;
+	outmsg.msg_controllen = sizeof(outcmsg);
+	outmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | MSG_EOR;
+
+	cmsg = CMSG_FIRSTHDR(&outmsg);
+	cmsg->cmsg_level = IPPROTO_SCTP;
+	cmsg->cmsg_type = SCTP_SNDRCV;
+	cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+	sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+	memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+	sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
+	sinfo->sinfo_assoc_id = ni->assoc_id;
+	outmsg.msg_controllen = cmsg->cmsg_len;
+
+	spin_lock(&ni->writequeue_lock);
+	for (;;) {
+		if (list_empty(&ni->writequeue))
+			break;
+		e = list_entry(ni->writequeue.next, struct writequeue_entry,
+			       list);
+		len = e->len;
+		offset = e->offset;
+		BUG_ON(len == 0 && e->users == 0);
+		spin_unlock(&ni->writequeue_lock);
+		kmap(e->page);
+
+		ret = 0;
+		if (len) {
+			iov.iov_base = page_address(e->page)+offset;
+			iov.iov_len = len;
+
+			ret = kernel_sendmsg(sctp_con.sock, &outmsg, &iov, 1,
+					     len);
+			if (ret == -EAGAIN) {
+				sctp_con.eagain_flag = 1;
+				goto out;
+			} else if (ret < 0)
+				goto send_error;
+		} else {
+			/* Don't starve people filling buffers */
+			schedule();
+		}
+
+		spin_lock(&ni->writequeue_lock);
+		e->offset += ret;
+		e->len -= ret;
+
+		if (e->len == 0 && e->users == 0) {
+			list_del(&e->list);
+			free_entry(e);
+			continue;
+		}
+	}
+	spin_unlock(&ni->writequeue_lock);
+ out:
+	return ret;
+
+ send_error:
+	log_print("Error sending to node %d %d", ni->nodeid, ret);
+	spin_lock(&ni->lock);
+	if (!test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
+		ni->assoc_id = 0;
+		spin_unlock(&ni->lock);
+		initiate_association(ni->nodeid);
+	} else
+		spin_unlock(&ni->lock);
+
+	return ret;
+}
+
+/* Try to send any messages that are pending */
+static void process_output_queue(void)
+{
+	struct list_head *list;
+	struct list_head *temp;
+
+	spin_lock_bh(&write_nodes_lock);
+	list_for_each_safe(list, temp, &write_nodes) {
+		struct nodeinfo *ni =
+		    list_entry(list, struct nodeinfo, write_list);
+		clear_bit(NI_WRITE_PENDING, &ni->flags);
+		list_del(&ni->write_list);
+
+		spin_unlock_bh(&write_nodes_lock);
+
+		send_to_sock(ni);
+		spin_lock_bh(&write_nodes_lock);
+	}
+	spin_unlock_bh(&write_nodes_lock);
+}
+
+/* Called after we've had -EAGAIN and been woken up */
+static void refill_write_queue(void)
+{
+	int i;
+
+	for (i=1; i<=max_nodeid; i++) {
+		struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+
+		if (ni) {
+			if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+				spin_lock_bh(&write_nodes_lock);
+				list_add_tail(&ni->write_list, &write_nodes);
+				spin_unlock_bh(&write_nodes_lock);
+			}
+		}
+	}
+}
+
+static void clean_one_writequeue(struct nodeinfo *ni)
+{
+	struct list_head *list;
+	struct list_head *temp;
+
+	spin_lock(&ni->writequeue_lock);
+	list_for_each_safe(list, temp, &ni->writequeue) {
+		struct writequeue_entry *e =
+			list_entry(list, struct writequeue_entry, list);
+		list_del(&e->list);
+		free_entry(e);
+	}
+	spin_unlock(&ni->writequeue_lock);
+}
+
+static void clean_writequeues(void)
+{
+	int i;
+
+	for (i=1; i<=max_nodeid; i++) {
+		struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+		if (ni)
+			clean_one_writequeue(ni);
+	}
+}
+
+
+static void dealloc_nodeinfo(void)
+{
+	int i;
+
+	for (i=1; i<=max_nodeid; i++) {
+		struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+		if (ni) {
+			idr_remove(&nodeinfo_idr, i);
+			kfree(ni);
+		}
+	}
+}
+
+int dlm_lowcomms_close(int nodeid)
+{
+	struct nodeinfo *ni;
+
+	ni = nodeid2nodeinfo(nodeid, 0);
+	if (!ni)
+		return -1;
+
+	spin_lock(&ni->lock);
+	if (ni->assoc_id) {
+		ni->assoc_id = 0;
+		/* Don't send shutdown here, sctp will just queue it
+		   till the node comes back up! */
+	}
+	spin_unlock(&ni->lock);
+
+	clean_one_writequeue(ni);
+	clear_bit(NI_INIT_PENDING, &ni->flags);
+	return 0;
+}
+
+static int write_list_empty(void)
+{
+	int status;
+
+	spin_lock_bh(&write_nodes_lock);
+	status = list_empty(&write_nodes);
+	spin_unlock_bh(&write_nodes_lock);
+
+	return status;
+}
+
+static int dlm_recvd(void *data)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	while (!kthread_should_stop()) {
+		int count = 0;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&lowcomms_recv_wait, &wait);
+		if (!test_bit(CF_READ_PENDING, &sctp_con.flags))
+			schedule();
+		remove_wait_queue(&lowcomms_recv_wait, &wait);
+		set_current_state(TASK_RUNNING);
+
+		if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
+			int ret;
+
+			do {
+				ret = receive_from_sock();
+
+				/* Don't starve out everyone else */
+				if (++count >= MAX_RX_MSG_COUNT) {
+					schedule();
+					count = 0;
+				}
+			} while (!kthread_should_stop() && ret >=0);
+		}
+		schedule();
+	}
+
+	return 0;
+}
+
+static int dlm_sendd(void *data)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
+
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (write_list_empty())
+			schedule();
+		set_current_state(TASK_RUNNING);
+
+		if (sctp_con.eagain_flag) {
+			sctp_con.eagain_flag = 0;
+			refill_write_queue();
+		}
+		process_output_queue();
+	}
+
+	remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
+
+	return 0;
+}
+
+static void daemons_stop(void)
+{
+	kthread_stop(recv_task);
+	kthread_stop(send_task);
+}
+
+static int daemons_start(void)
+{
+	struct task_struct *p;
+	int error;
+
+	p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
+	error = IS_ERR(p);
+       	if (error) {
+		log_print("can't start dlm_recvd %d", error);
+		return error;
+	}
+	recv_task = p;
+
+	p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
+	error = IS_ERR(p);
+       	if (error) {
+		log_print("can't start dlm_sendd %d", error);
+		kthread_stop(recv_task);
+		return error;
+	}
+	send_task = p;
+
+	return 0;
+}
+
+/*
+ * This is quite likely to sleep...
+ */
+int dlm_lowcomms_start(void)
+{
+	int error;
+
+	error = init_sock();
+	if (error)
+		goto fail_sock;
+	error = daemons_start();
+	if (error)
+		goto fail_sock;
+	atomic_set(&accepting, 1);
+	return 0;
+
+ fail_sock:
+	close_connection();
+	return error;
+}
+
+/* Set all the activity flags to prevent any socket activity. */
+
+void dlm_lowcomms_stop(void)
+{
+	atomic_set(&accepting, 0);
+	sctp_con.flags = 0x7;
+	daemons_stop();
+	clean_writequeues();
+	close_connection();
+	dealloc_nodeinfo();
+	max_nodeid = 0;
+}
+
+int dlm_lowcomms_init(void)
+{
+	init_waitqueue_head(&lowcomms_recv_wait);
+	spin_lock_init(&write_nodes_lock);
+	INIT_LIST_HEAD(&write_nodes);
+	init_rwsem(&nodeinfo_lock);
+	return 0;
+}
+
+void dlm_lowcomms_exit(void)
+{
+	int i;
+
+	for (i = 0; i < dlm_local_count; i++)
+		kfree(dlm_local_addr[i]);
+	dlm_local_count = 0;
+	dlm_local_nodeid = 0;
+}
+
diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h
new file mode 100644
index 0000000..6c04bb0
--- /dev/null
+++ b/fs/dlm/lowcomms.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOWCOMMS_DOT_H__
+#define __LOWCOMMS_DOT_H__
+
+int dlm_lowcomms_init(void);
+void dlm_lowcomms_exit(void);
+int dlm_lowcomms_start(void);
+void dlm_lowcomms_stop(void);
+int dlm_lowcomms_close(int nodeid);
+void *dlm_lowcomms_get_buffer(int nodeid, int len, int allocation, char **ppc);
+void dlm_lowcomms_commit_buffer(void *mh);
+
+#endif				/* __LOWCOMMS_DOT_H__ */
+
diff --git a/fs/dlm/lvb_table.h b/fs/dlm/lvb_table.h
new file mode 100644
index 0000000..cc3e92f
--- /dev/null
+++ b/fs/dlm/lvb_table.h
@@ -0,0 +1,18 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LVB_TABLE_DOT_H__
+#define __LVB_TABLE_DOT_H__
+
+extern const int dlm_lvb_operations[8][8];
+
+#endif
diff --git a/fs/dlm/main.c b/fs/dlm/main.c
new file mode 100644
index 0000000..a8da8dc
--- /dev/null
+++ b/fs/dlm/main.c
@@ -0,0 +1,97 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "lock.h"
+#include "user.h"
+#include "memory.h"
+#include "lowcomms.h"
+#include "config.h"
+
+#ifdef CONFIG_DLM_DEBUG
+int dlm_register_debugfs(void);
+void dlm_unregister_debugfs(void);
+#else
+static inline int dlm_register_debugfs(void) { return 0; }
+static inline void dlm_unregister_debugfs(void) { }
+#endif
+
+static int __init init_dlm(void)
+{
+	int error;
+
+	error = dlm_memory_init();
+	if (error)
+		goto out;
+
+	error = dlm_lockspace_init();
+	if (error)
+		goto out_mem;
+
+	error = dlm_config_init();
+	if (error)
+		goto out_lockspace;
+
+	error = dlm_register_debugfs();
+	if (error)
+		goto out_config;
+
+	error = dlm_lowcomms_init();
+	if (error)
+		goto out_debug;
+
+	error = dlm_user_init();
+	if (error)
+		goto out_lowcomms;
+
+	printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
+
+	return 0;
+
+ out_lowcomms:
+	dlm_lowcomms_exit();
+ out_debug:
+	dlm_unregister_debugfs();
+ out_config:
+	dlm_config_exit();
+ out_lockspace:
+	dlm_lockspace_exit();
+ out_mem:
+	dlm_memory_exit();
+ out:
+	return error;
+}
+
+static void __exit exit_dlm(void)
+{
+	dlm_user_exit();
+	dlm_lowcomms_exit();
+	dlm_config_exit();
+	dlm_memory_exit();
+	dlm_lockspace_exit();
+	dlm_unregister_debugfs();
+}
+
+module_init(init_dlm);
+module_exit(exit_dlm);
+
+MODULE_DESCRIPTION("Distributed Lock Manager");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL_GPL(dlm_new_lockspace);
+EXPORT_SYMBOL_GPL(dlm_release_lockspace);
+EXPORT_SYMBOL_GPL(dlm_lock);
+EXPORT_SYMBOL_GPL(dlm_unlock);
+
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
new file mode 100644
index 0000000..a3f7de7
--- /dev/null
+++ b/fs/dlm/member.c
@@ -0,0 +1,327 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "recoverd.h"
+#include "recover.h"
+#include "rcom.h"
+#include "config.h"
+
+/*
+ * Following called by dlm_recoverd thread
+ */
+
+static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
+{
+	struct dlm_member *memb = NULL;
+	struct list_head *tmp;
+	struct list_head *newlist = &new->list;
+	struct list_head *head = &ls->ls_nodes;
+
+	list_for_each(tmp, head) {
+		memb = list_entry(tmp, struct dlm_member, list);
+		if (new->nodeid < memb->nodeid)
+			break;
+	}
+
+	if (!memb)
+		list_add_tail(newlist, head);
+	else {
+		/* FIXME: can use list macro here */
+		newlist->prev = tmp->prev;
+		newlist->next = tmp;
+		tmp->prev->next = newlist;
+		tmp->prev = newlist;
+	}
+}
+
+static int dlm_add_member(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_member *memb;
+	int w;
+
+	memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+	if (!memb)
+		return -ENOMEM;
+
+	w = dlm_node_weight(ls->ls_name, nodeid);
+	if (w < 0)
+		return w;
+
+	memb->nodeid = nodeid;
+	memb->weight = w;
+	add_ordered_member(ls, memb);
+	ls->ls_num_nodes++;
+	return 0;
+}
+
+static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb)
+{
+	list_move(&memb->list, &ls->ls_nodes_gone);
+	ls->ls_num_nodes--;
+}
+
+static int dlm_is_member(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_member *memb;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (memb->nodeid == nodeid)
+			return 1;
+	}
+	return 0;
+}
+
+int dlm_is_removed(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_member *memb;
+
+	list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
+		if (memb->nodeid == nodeid)
+			return 1;
+	}
+	return 0;
+}
+
+static void clear_memb_list(struct list_head *head)
+{
+	struct dlm_member *memb;
+
+	while (!list_empty(head)) {
+		memb = list_entry(head->next, struct dlm_member, list);
+		list_del(&memb->list);
+		kfree(memb);
+	}
+}
+
+void dlm_clear_members(struct dlm_ls *ls)
+{
+	clear_memb_list(&ls->ls_nodes);
+	ls->ls_num_nodes = 0;
+}
+
+void dlm_clear_members_gone(struct dlm_ls *ls)
+{
+	clear_memb_list(&ls->ls_nodes_gone);
+}
+
+static void make_member_array(struct dlm_ls *ls)
+{
+	struct dlm_member *memb;
+	int i, w, x = 0, total = 0, all_zero = 0, *array;
+
+	kfree(ls->ls_node_array);
+	ls->ls_node_array = NULL;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (memb->weight)
+			total += memb->weight;
+	}
+
+	/* all nodes revert to weight of 1 if all have weight 0 */
+
+	if (!total) {
+		total = ls->ls_num_nodes;
+		all_zero = 1;
+	}
+
+	ls->ls_total_weight = total;
+
+	array = kmalloc(sizeof(int) * total, GFP_KERNEL);
+	if (!array)
+		return;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (!all_zero && !memb->weight)
+			continue;
+
+		if (all_zero)
+			w = 1;
+		else
+			w = memb->weight;
+
+		DLM_ASSERT(x < total, printk("total %d x %d\n", total, x););
+
+		for (i = 0; i < w; i++)
+			array[x++] = memb->nodeid;
+	}
+
+	ls->ls_node_array = array;
+}
+
+/* send a status request to all members just to establish comms connections */
+
+static int ping_members(struct dlm_ls *ls)
+{
+	struct dlm_member *memb;
+	int error = 0;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		error = dlm_recovery_stopped(ls);
+		if (error)
+			break;
+		error = dlm_rcom_status(ls, memb->nodeid);
+		if (error)
+			break;
+	}
+	if (error)
+		log_debug(ls, "ping_members aborted %d last nodeid %d",
+			  error, ls->ls_recover_nodeid);
+	return error;
+}
+
+int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
+{
+	struct dlm_member *memb, *safe;
+	int i, error, found, pos = 0, neg = 0, low = -1;
+
+	/* move departed members from ls_nodes to ls_nodes_gone */
+
+	list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) {
+		found = 0;
+		for (i = 0; i < rv->node_count; i++) {
+			if (memb->nodeid == rv->nodeids[i]) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			neg++;
+			dlm_remove_member(ls, memb);
+			log_debug(ls, "remove member %d", memb->nodeid);
+		}
+	}
+
+	/* add new members to ls_nodes */
+
+	for (i = 0; i < rv->node_count; i++) {
+		if (dlm_is_member(ls, rv->nodeids[i]))
+			continue;
+		dlm_add_member(ls, rv->nodeids[i]);
+		pos++;
+		log_debug(ls, "add member %d", rv->nodeids[i]);
+	}
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		if (low == -1 || memb->nodeid < low)
+			low = memb->nodeid;
+	}
+	ls->ls_low_nodeid = low;
+
+	make_member_array(ls);
+	dlm_set_recover_status(ls, DLM_RS_NODES);
+	*neg_out = neg;
+
+	error = ping_members(ls);
+	if (error)
+		goto out;
+
+	error = dlm_recover_members_wait(ls);
+ out:
+	log_debug(ls, "total members %d error %d", ls->ls_num_nodes, error);
+	return error;
+}
+
+/*
+ * Following called from lockspace.c
+ */
+
+int dlm_ls_stop(struct dlm_ls *ls)
+{
+	int new;
+
+	/*
+	 * A stop cancels any recovery that's in progress (see RECOVERY_STOP,
+	 * dlm_recovery_stopped()) and prevents any new locks from being
+	 * processed (see RUNNING, dlm_locking_stopped()).
+	 */
+
+	spin_lock(&ls->ls_recover_lock);
+	set_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
+	ls->ls_recover_seq++;
+	spin_unlock(&ls->ls_recover_lock);
+
+	/*
+	 * This in_recovery lock does two things:
+	 *
+	 * 1) Keeps this function from returning until all threads are out
+	 *    of locking routines and locking is truely stopped.
+	 * 2) Keeps any new requests from being processed until it's unlocked
+	 *    when recovery is complete.
+	 */
+
+	if (new)
+		down_write(&ls->ls_in_recovery);
+
+	/*
+	 * The recoverd suspend/resume makes sure that dlm_recoverd (if
+	 * running) has noticed the clearing of RUNNING above and quit
+	 * processing the previous recovery.  This will be true for all nodes
+	 * before any nodes start the new recovery.
+	 */
+
+	dlm_recoverd_suspend(ls);
+	ls->ls_recover_status = 0;
+	dlm_recoverd_resume(ls);
+	return 0;
+}
+
+int dlm_ls_start(struct dlm_ls *ls)
+{
+	struct dlm_recover *rv = NULL, *rv_old;
+	int *ids = NULL;
+	int error, count;
+
+	rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
+	if (!rv)
+		return -ENOMEM;
+
+	error = count = dlm_nodeid_list(ls->ls_name, &ids);
+	if (error <= 0)
+		goto fail;
+
+	spin_lock(&ls->ls_recover_lock);
+
+	/* the lockspace needs to be stopped before it can be started */
+
+	if (!dlm_locking_stopped(ls)) {
+		spin_unlock(&ls->ls_recover_lock);
+		log_error(ls, "start ignored: lockspace running");
+		error = -EINVAL;
+		goto fail;
+	}
+
+	rv->nodeids = ids;
+	rv->node_count = count;
+	rv->seq = ++ls->ls_recover_seq;
+	rv_old = ls->ls_recover_args;
+	ls->ls_recover_args = rv;
+	spin_unlock(&ls->ls_recover_lock);
+
+	if (rv_old) {
+		kfree(rv_old->nodeids);
+		kfree(rv_old);
+	}
+
+	dlm_recoverd_kick(ls);
+	return 0;
+
+ fail:
+	kfree(rv);
+	kfree(ids);
+	return error;
+}
+
diff --git a/fs/dlm/member.h b/fs/dlm/member.h
new file mode 100644
index 0000000..927c08c
--- /dev/null
+++ b/fs/dlm/member.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MEMBER_DOT_H__
+#define __MEMBER_DOT_H__
+
+int dlm_ls_stop(struct dlm_ls *ls);
+int dlm_ls_start(struct dlm_ls *ls);
+void dlm_clear_members(struct dlm_ls *ls);
+void dlm_clear_members_gone(struct dlm_ls *ls);
+int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out);
+int dlm_is_removed(struct dlm_ls *ls, int nodeid);
+
+#endif                          /* __MEMBER_DOT_H__ */
+
diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c
new file mode 100644
index 0000000..989b608
--- /dev/null
+++ b/fs/dlm/memory.c
@@ -0,0 +1,116 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "config.h"
+#include "memory.h"
+
+static kmem_cache_t *lkb_cache;
+
+
+int dlm_memory_init(void)
+{
+	int ret = 0;
+
+	lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
+				__alignof__(struct dlm_lkb), 0, NULL, NULL);
+	if (!lkb_cache)
+		ret = -ENOMEM;
+	return ret;
+}
+
+void dlm_memory_exit(void)
+{
+	if (lkb_cache)
+		kmem_cache_destroy(lkb_cache);
+}
+
+char *allocate_lvb(struct dlm_ls *ls)
+{
+	char *p;
+
+	p = kmalloc(ls->ls_lvblen, GFP_KERNEL);
+	if (p)
+		memset(p, 0, ls->ls_lvblen);
+	return p;
+}
+
+void free_lvb(char *p)
+{
+	kfree(p);
+}
+
+/* FIXME: have some minimal space built-in to rsb for the name and
+   kmalloc a separate name if needed, like dentries are done */
+
+struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen)
+{
+	struct dlm_rsb *r;
+
+	DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);
+
+	r = kmalloc(sizeof(*r) + namelen, GFP_KERNEL);
+	if (r)
+		memset(r, 0, sizeof(*r) + namelen);
+	return r;
+}
+
+void free_rsb(struct dlm_rsb *r)
+{
+	if (r->res_lvbptr)
+		free_lvb(r->res_lvbptr);
+	kfree(r);
+}
+
+struct dlm_lkb *allocate_lkb(struct dlm_ls *ls)
+{
+	struct dlm_lkb *lkb;
+
+	lkb = kmem_cache_alloc(lkb_cache, GFP_KERNEL);
+	if (lkb)
+		memset(lkb, 0, sizeof(*lkb));
+	return lkb;
+}
+
+void free_lkb(struct dlm_lkb *lkb)
+{
+	if (lkb->lkb_flags & DLM_IFL_USER) {
+		struct dlm_user_args *ua;
+		ua = (struct dlm_user_args *)lkb->lkb_astparam;
+		if (ua) {
+			if (ua->lksb.sb_lvbptr)
+				kfree(ua->lksb.sb_lvbptr);
+			kfree(ua);
+		}
+	}
+	kmem_cache_free(lkb_cache, lkb);
+}
+
+struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen)
+{
+	struct dlm_direntry *de;
+
+	DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,
+		   printk("namelen = %d\n", namelen););
+
+	de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL);
+	if (de)
+		memset(de, 0, sizeof(*de) + namelen);
+	return de;
+}
+
+void free_direntry(struct dlm_direntry *de)
+{
+	kfree(de);
+}
+
diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h
new file mode 100644
index 0000000..6ead158
--- /dev/null
+++ b/fs/dlm/memory.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MEMORY_DOT_H__
+#define __MEMORY_DOT_H__
+
+int dlm_memory_init(void);
+void dlm_memory_exit(void);
+struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen);
+void free_rsb(struct dlm_rsb *r);
+struct dlm_lkb *allocate_lkb(struct dlm_ls *ls);
+void free_lkb(struct dlm_lkb *l);
+struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen);
+void free_direntry(struct dlm_direntry *de);
+char *allocate_lvb(struct dlm_ls *ls);
+void free_lvb(char *l);
+
+#endif		/* __MEMORY_DOT_H__ */
+
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
new file mode 100644
index 0000000..c9b1c3d
--- /dev/null
+++ b/fs/dlm/midcomms.c
@@ -0,0 +1,140 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * midcomms.c
+ *
+ * This is the appallingly named "mid-level" comms layer.
+ *
+ * Its purpose is to take packets from the "real" comms layer,
+ * split them up into packets and pass them to the interested
+ * part of the locking mechanism.
+ *
+ * It also takes messages from the locking layer, formats them
+ * into packets and sends them to the comms layer.
+ */
+
+#include "dlm_internal.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "rcom.h"
+#include "lock.h"
+#include "midcomms.h"
+
+
+static void copy_from_cb(void *dst, const void *base, unsigned offset,
+			 unsigned len, unsigned limit)
+{
+	unsigned copy = len;
+
+	if ((copy + offset) > limit)
+		copy = limit - offset;
+	memcpy(dst, base + offset, copy);
+	len -= copy;
+	if (len)
+		memcpy(dst + copy, base, len);
+}
+
+/*
+ * Called from the low-level comms layer to process a buffer of
+ * commands.
+ *
+ * Only complete messages are processed here, any "spare" bytes from
+ * the end of a buffer are saved and tacked onto the front of the next
+ * message that comes in. I doubt this will happen very often but we
+ * need to be able to cope with it and I don't want the task to be waiting
+ * for packets to come in when there is useful work to be done.
+ */
+
+int dlm_process_incoming_buffer(int nodeid, const void *base,
+				unsigned offset, unsigned len, unsigned limit)
+{
+	unsigned char __tmp[DLM_INBUF_LEN];
+	struct dlm_header *msg = (struct dlm_header *) __tmp;
+	int ret = 0;
+	int err = 0;
+	uint16_t msglen;
+	uint32_t lockspace;
+
+	while (len > sizeof(struct dlm_header)) {
+
+		/* Copy just the header to check the total length.  The
+		   message may wrap around the end of the buffer back to the
+		   start, so we need to use a temp buffer and copy_from_cb. */
+
+		copy_from_cb(msg, base, offset, sizeof(struct dlm_header),
+			     limit);
+
+		msglen = le16_to_cpu(msg->h_length);
+		lockspace = msg->h_lockspace;
+
+		err = -EINVAL;
+		if (msglen < sizeof(struct dlm_header))
+			break;
+		err = -E2BIG;
+		if (msglen > dlm_config.buffer_size) {
+			log_print("message size %d from %d too big, buf len %d",
+				  msglen, nodeid, len);
+			break;
+		}
+		err = 0;
+
+		/* If only part of the full message is contained in this
+		   buffer, then do nothing and wait for lowcomms to call
+		   us again later with more data.  We return 0 meaning
+		   we've consumed none of the input buffer. */
+
+		if (msglen > len)
+			break;
+
+		/* Allocate a larger temp buffer if the full message won't fit
+		   in the buffer on the stack (which should work for most
+		   ordinary messages). */
+
+		if (msglen > sizeof(__tmp) &&
+		    msg == (struct dlm_header *) __tmp) {
+			msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+			if (msg == NULL)
+				return ret;
+		}
+
+		copy_from_cb(msg, base, offset, msglen, limit);
+
+		BUG_ON(lockspace != msg->h_lockspace);
+
+		ret += msglen;
+		offset += msglen;
+		offset &= (limit - 1);
+		len -= msglen;
+
+		switch (msg->h_cmd) {
+		case DLM_MSG:
+			dlm_receive_message(msg, nodeid, 0);
+			break;
+
+		case DLM_RCOM:
+			dlm_receive_rcom(msg, nodeid);
+			break;
+
+		default:
+			log_print("unknown msg type %x from %u: %u %u %u %u",
+				  msg->h_cmd, nodeid, msglen, len, offset, ret);
+		}
+	}
+
+	if (msg != (struct dlm_header *) __tmp)
+		kfree(msg);
+
+	return err ? err : ret;
+}
+
diff --git a/fs/dlm/midcomms.h b/fs/dlm/midcomms.h
new file mode 100644
index 0000000..95852a5
--- /dev/null
+++ b/fs/dlm/midcomms.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MIDCOMMS_DOT_H__
+#define __MIDCOMMS_DOT_H__
+
+int dlm_process_incoming_buffer(int nodeid, const void *base, unsigned offset,
+				unsigned len, unsigned limit);
+
+#endif				/* __MIDCOMMS_DOT_H__ */
+
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
new file mode 100644
index 0000000..518239a
--- /dev/null
+++ b/fs/dlm/rcom.c
@@ -0,0 +1,472 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "lowcomms.h"
+#include "midcomms.h"
+#include "rcom.h"
+#include "recover.h"
+#include "dir.h"
+#include "config.h"
+#include "memory.h"
+#include "lock.h"
+#include "util.h"
+
+
+static int rcom_response(struct dlm_ls *ls)
+{
+	return test_bit(LSFL_RCOM_READY, &ls->ls_flags);
+}
+
+static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len,
+		       struct dlm_rcom **rc_ret, struct dlm_mhandle **mh_ret)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	char *mb;
+	int mb_len = sizeof(struct dlm_rcom) + len;
+
+	mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
+	if (!mh) {
+		log_print("create_rcom to %d type %d len %d ENOBUFS",
+			  to_nodeid, type, len);
+		return -ENOBUFS;
+	}
+	memset(mb, 0, mb_len);
+
+	rc = (struct dlm_rcom *) mb;
+
+	rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+	rc->rc_header.h_lockspace = ls->ls_global_id;
+	rc->rc_header.h_nodeid = dlm_our_nodeid();
+	rc->rc_header.h_length = mb_len;
+	rc->rc_header.h_cmd = DLM_RCOM;
+
+	rc->rc_type = type;
+
+	*mh_ret = mh;
+	*rc_ret = rc;
+	return 0;
+}
+
+static void send_rcom(struct dlm_ls *ls, struct dlm_mhandle *mh,
+		      struct dlm_rcom *rc)
+{
+	dlm_rcom_out(rc);
+	dlm_lowcomms_commit_buffer(mh);
+}
+
+/* When replying to a status request, a node also sends back its
+   configuration values.  The requesting node then checks that the remote
+   node is configured the same way as itself. */
+
+static void make_config(struct dlm_ls *ls, struct rcom_config *rf)
+{
+	rf->rf_lvblen = ls->ls_lvblen;
+	rf->rf_lsflags = ls->ls_exflags;
+}
+
+static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid)
+{
+	if (rf->rf_lvblen != ls->ls_lvblen ||
+	    rf->rf_lsflags != ls->ls_exflags) {
+		log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
+			  ls->ls_lvblen, ls->ls_exflags,
+			  nodeid, rf->rf_lvblen, rf->rf_lsflags);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error = 0;
+
+	memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+	ls->ls_recover_nodeid = nodeid;
+
+	if (nodeid == dlm_our_nodeid()) {
+		rc = (struct dlm_rcom *) ls->ls_recover_buf;
+		rc->rc_result = dlm_recover_status(ls);
+		goto out;
+	}
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh);
+	if (error)
+		goto out;
+	rc->rc_id = ++ls->ls_rcom_seq;
+
+	send_rcom(ls, mh, rc);
+
+	error = dlm_wait_function(ls, &rcom_response);
+	clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
+	if (error)
+		goto out;
+
+	rc = (struct dlm_rcom *) ls->ls_recover_buf;
+
+	if (rc->rc_result == -ESRCH) {
+		/* we pretend the remote lockspace exists with 0 status */
+		log_debug(ls, "remote node %d not ready", nodeid);
+		rc->rc_result = 0;
+	} else
+		error = check_config(ls, (struct rcom_config *) rc->rc_buf,
+				     nodeid);
+	/* the caller looks at rc_result for the remote recovery status */
+ out:
+	return error;
+}
+
+static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, nodeid = rc_in->rc_header.h_nodeid;
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_STATUS_REPLY,
+			    sizeof(struct rcom_config), &rc, &mh);
+	if (error)
+		return;
+	rc->rc_id = rc_in->rc_id;
+	rc->rc_result = dlm_recover_status(ls);
+	make_config(ls, (struct rcom_config *) rc->rc_buf);
+
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_sync_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	if (rc_in->rc_id != ls->ls_rcom_seq) {
+		log_debug(ls, "reject old reply %d got %llx wanted %llx",
+			  rc_in->rc_type, rc_in->rc_id, ls->ls_rcom_seq);
+		return;
+	}
+	memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length);
+	set_bit(LSFL_RCOM_READY, &ls->ls_flags);
+	wake_up(&ls->ls_wait_general);
+}
+
+static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	receive_sync_reply(ls, rc_in);
+}
+
+int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error = 0, len = sizeof(struct dlm_rcom);
+
+	memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+	ls->ls_recover_nodeid = nodeid;
+
+	if (nodeid == dlm_our_nodeid()) {
+		dlm_copy_master_names(ls, last_name, last_len,
+		                      ls->ls_recover_buf + len,
+		                      dlm_config.buffer_size - len, nodeid);
+		goto out;
+	}
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_NAMES, last_len, &rc, &mh);
+	if (error)
+		goto out;
+	memcpy(rc->rc_buf, last_name, last_len);
+	rc->rc_id = ++ls->ls_rcom_seq;
+
+	send_rcom(ls, mh, rc);
+
+	error = dlm_wait_function(ls, &rcom_response);
+	clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
+ out:
+	return error;
+}
+
+static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, inlen, outlen;
+	int nodeid = rc_in->rc_header.h_nodeid;
+	uint32_t status = dlm_recover_status(ls);
+
+	/*
+	 * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while
+	 * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes).
+	 * It could only happen in rare cases where we get a late NAMES
+	 * message from a previous instance of recovery.
+	 */
+
+	if (!(status & DLM_RS_NODES)) {
+		log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid);
+		return;
+	}
+
+	nodeid = rc_in->rc_header.h_nodeid;
+	inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
+	outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom);
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh);
+	if (error)
+		return;
+	rc->rc_id = rc_in->rc_id;
+
+	dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen,
+			      nodeid);
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_names_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	receive_sync_reply(ls, rc_in);
+}
+
+int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	struct dlm_ls *ls = r->res_ls;
+	int error;
+
+	error = create_rcom(ls, dir_nodeid, DLM_RCOM_LOOKUP, r->res_length,
+			    &rc, &mh);
+	if (error)
+		goto out;
+	memcpy(rc->rc_buf, r->res_name, r->res_length);
+	rc->rc_id = (unsigned long) r;
+
+	send_rcom(ls, mh, rc);
+ out:
+	return error;
+}
+
+static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, ret_nodeid, nodeid = rc_in->rc_header.h_nodeid;
+	int len = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_LOOKUP_REPLY, 0, &rc, &mh);
+	if (error)
+		return;
+
+	error = dlm_dir_lookup(ls, nodeid, rc_in->rc_buf, len, &ret_nodeid);
+	if (error)
+		ret_nodeid = error;
+	rc->rc_result = ret_nodeid;
+	rc->rc_id = rc_in->rc_id;
+
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_lookup_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	dlm_recover_master_reply(ls, rc_in);
+}
+
+static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb,
+			   struct rcom_lock *rl)
+{
+	memset(rl, 0, sizeof(*rl));
+
+	rl->rl_ownpid = lkb->lkb_ownpid;
+	rl->rl_lkid = lkb->lkb_id;
+	rl->rl_exflags = lkb->lkb_exflags;
+	rl->rl_flags = lkb->lkb_flags;
+	rl->rl_lvbseq = lkb->lkb_lvbseq;
+	rl->rl_rqmode = lkb->lkb_rqmode;
+	rl->rl_grmode = lkb->lkb_grmode;
+	rl->rl_status = lkb->lkb_status;
+	rl->rl_wait_type = lkb->lkb_wait_type;
+
+	if (lkb->lkb_bastaddr)
+		rl->rl_asts |= AST_BAST;
+	if (lkb->lkb_astaddr)
+		rl->rl_asts |= AST_COMP;
+
+	rl->rl_namelen = r->res_length;
+	memcpy(rl->rl_name, r->res_name, r->res_length);
+
+	/* FIXME: might we have an lvb without DLM_LKF_VALBLK set ?
+	   If so, receive_rcom_lock_args() won't take this copy. */
+
+	if (lkb->lkb_lvbptr)
+		memcpy(rl->rl_lvb, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+}
+
+int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+	struct dlm_ls *ls = r->res_ls;
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	struct rcom_lock *rl;
+	int error, len = sizeof(struct rcom_lock);
+
+	if (lkb->lkb_lvbptr)
+		len += ls->ls_lvblen;
+
+	error = create_rcom(ls, r->res_nodeid, DLM_RCOM_LOCK, len, &rc, &mh);
+	if (error)
+		goto out;
+
+	rl = (struct rcom_lock *) rc->rc_buf;
+	pack_rcom_lock(r, lkb, rl);
+	rc->rc_id = (unsigned long) r;
+
+	send_rcom(ls, mh, rc);
+ out:
+	return error;
+}
+
+static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	int error, nodeid = rc_in->rc_header.h_nodeid;
+
+	dlm_recover_master_copy(ls, rc_in);
+
+	error = create_rcom(ls, nodeid, DLM_RCOM_LOCK_REPLY,
+			    sizeof(struct rcom_lock), &rc, &mh);
+	if (error)
+		return;
+
+	/* We send back the same rcom_lock struct we received, but
+	   dlm_recover_master_copy() has filled in rl_remid and rl_result */
+
+	memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock));
+	rc->rc_id = rc_in->rc_id;
+
+	send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+	uint32_t status = dlm_recover_status(ls);
+
+	if (!(status & DLM_RS_DIR)) {
+		log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u",
+			  rc_in->rc_header.h_nodeid);
+		return;
+	}
+
+	dlm_recover_process_copy(ls, rc_in);
+}
+
+static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
+{
+	struct dlm_rcom *rc;
+	struct dlm_mhandle *mh;
+	char *mb;
+	int mb_len = sizeof(struct dlm_rcom);
+
+	mh = dlm_lowcomms_get_buffer(nodeid, mb_len, GFP_KERNEL, &mb);
+	if (!mh)
+		return -ENOBUFS;
+	memset(mb, 0, mb_len);
+
+	rc = (struct dlm_rcom *) mb;
+
+	rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+	rc->rc_header.h_lockspace = rc_in->rc_header.h_lockspace;
+	rc->rc_header.h_nodeid = dlm_our_nodeid();
+	rc->rc_header.h_length = mb_len;
+	rc->rc_header.h_cmd = DLM_RCOM;
+
+	rc->rc_type = DLM_RCOM_STATUS_REPLY;
+	rc->rc_id = rc_in->rc_id;
+	rc->rc_result = -ESRCH;
+
+	dlm_rcom_out(rc);
+	dlm_lowcomms_commit_buffer(mh);
+
+	return 0;
+}
+
+/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
+   recovery-only comms are sent through here. */
+
+void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
+{
+	struct dlm_rcom *rc = (struct dlm_rcom *) hd;
+	struct dlm_ls *ls;
+
+	dlm_rcom_in(rc);
+
+	/* If the lockspace doesn't exist then still send a status message
+	   back; it's possible that it just doesn't have its global_id yet. */
+
+	ls = dlm_find_lockspace_global(hd->h_lockspace);
+	if (!ls) {
+		log_print("lockspace %x from %d not found",
+			  hd->h_lockspace, nodeid);
+		send_ls_not_ready(nodeid, rc);
+		return;
+	}
+
+	if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
+		log_error(ls, "ignoring recovery message %x from %d",
+			  rc->rc_type, nodeid);
+		goto out;
+	}
+
+	if (nodeid != rc->rc_header.h_nodeid) {
+		log_error(ls, "bad rcom nodeid %d from %d",
+			  rc->rc_header.h_nodeid, nodeid);
+		goto out;
+	}
+
+	switch (rc->rc_type) {
+	case DLM_RCOM_STATUS:
+		receive_rcom_status(ls, rc);
+		break;
+
+	case DLM_RCOM_NAMES:
+		receive_rcom_names(ls, rc);
+		break;
+
+	case DLM_RCOM_LOOKUP:
+		receive_rcom_lookup(ls, rc);
+		break;
+
+	case DLM_RCOM_LOCK:
+		receive_rcom_lock(ls, rc);
+		break;
+
+	case DLM_RCOM_STATUS_REPLY:
+		receive_rcom_status_reply(ls, rc);
+		break;
+
+	case DLM_RCOM_NAMES_REPLY:
+		receive_rcom_names_reply(ls, rc);
+		break;
+
+	case DLM_RCOM_LOOKUP_REPLY:
+		receive_rcom_lookup_reply(ls, rc);
+		break;
+
+	case DLM_RCOM_LOCK_REPLY:
+		receive_rcom_lock_reply(ls, rc);
+		break;
+
+	default:
+		DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type););
+	}
+ out:
+	dlm_put_lockspace(ls);
+}
+
diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h
new file mode 100644
index 0000000..d798432
--- /dev/null
+++ b/fs/dlm/rcom.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RCOM_DOT_H__
+#define __RCOM_DOT_H__
+
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid);
+int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
+int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
+int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+void dlm_receive_rcom(struct dlm_header *hd, int nodeid);
+
+#endif
+
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
new file mode 100644
index 0000000..a5e6d18
--- /dev/null
+++ b/fs/dlm/recover.c
@@ -0,0 +1,765 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "dir.h"
+#include "config.h"
+#include "ast.h"
+#include "memory.h"
+#include "rcom.h"
+#include "lock.h"
+#include "lowcomms.h"
+#include "member.h"
+#include "recover.h"
+
+
+/*
+ * Recovery waiting routines: these functions wait for a particular reply from
+ * a remote node, or for the remote node to report a certain status.  They need
+ * to abort if the lockspace is stopped indicating a node has failed (perhaps
+ * the one being waited for).
+ */
+
+/*
+ * Wait until given function returns non-zero or lockspace is stopped
+ * (LS_RECOVERY_STOP set due to failure of a node in ls_nodes).  When another
+ * function thinks it could have completed the waited-on task, they should wake
+ * up ls_wait_general to get an immediate response rather than waiting for the
+ * timer to detect the result.  A timer wakes us up periodically while waiting
+ * to see if we should abort due to a node failure.  This should only be called
+ * by the dlm_recoverd thread.
+ */
+
+static void dlm_wait_timer_fn(unsigned long data)
+{
+	struct dlm_ls *ls = (struct dlm_ls *) data;
+	mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ));
+	wake_up(&ls->ls_wait_general);
+}
+
+int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))
+{
+	int error = 0;
+
+	init_timer(&ls->ls_timer);
+	ls->ls_timer.function = dlm_wait_timer_fn;
+	ls->ls_timer.data = (long) ls;
+	ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ);
+	add_timer(&ls->ls_timer);
+
+	wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
+	del_timer_sync(&ls->ls_timer);
+
+	if (dlm_recovery_stopped(ls)) {
+		log_debug(ls, "dlm_wait_function aborted");
+		error = -EINTR;
+	}
+	return error;
+}
+
+/*
+ * An efficient way for all nodes to wait for all others to have a certain
+ * status.  The node with the lowest nodeid polls all the others for their
+ * status (wait_status_all) and all the others poll the node with the low id
+ * for its accumulated result (wait_status_low).  When all nodes have set
+ * status flag X, then status flag X_ALL will be set on the low nodeid.
+ */
+
+uint32_t dlm_recover_status(struct dlm_ls *ls)
+{
+	uint32_t status;
+	spin_lock(&ls->ls_recover_lock);
+	status = ls->ls_recover_status;
+	spin_unlock(&ls->ls_recover_lock);
+	return status;
+}
+
+void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status)
+{
+	spin_lock(&ls->ls_recover_lock);
+	ls->ls_recover_status |= status;
+	spin_unlock(&ls->ls_recover_lock);
+}
+
+static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)
+{
+	struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
+	struct dlm_member *memb;
+	int error = 0, delay;
+
+	list_for_each_entry(memb, &ls->ls_nodes, list) {
+		delay = 0;
+		for (;;) {
+			if (dlm_recovery_stopped(ls)) {
+				error = -EINTR;
+				goto out;
+			}
+
+			error = dlm_rcom_status(ls, memb->nodeid);
+			if (error)
+				goto out;
+
+			if (rc->rc_result & wait_status)
+				break;
+			if (delay < 1000)
+				delay += 20;
+			msleep(delay);
+		}
+	}
+ out:
+	return error;
+}
+
+static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status)
+{
+	struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
+	int error = 0, delay = 0, nodeid = ls->ls_low_nodeid;
+
+	for (;;) {
+		if (dlm_recovery_stopped(ls)) {
+			error = -EINTR;
+			goto out;
+		}
+
+		error = dlm_rcom_status(ls, nodeid);
+		if (error)
+			break;
+
+		if (rc->rc_result & wait_status)
+			break;
+		if (delay < 1000)
+			delay += 20;
+		msleep(delay);
+	}
+ out:
+	return error;
+}
+
+static int wait_status(struct dlm_ls *ls, uint32_t status)
+{
+	uint32_t status_all = status << 1;
+	int error;
+
+	if (ls->ls_low_nodeid == dlm_our_nodeid()) {
+		error = wait_status_all(ls, status);
+		if (!error)
+			dlm_set_recover_status(ls, status_all);
+	} else
+		error = wait_status_low(ls, status_all);
+
+	return error;
+}
+
+int dlm_recover_members_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_NODES);
+}
+
+int dlm_recover_directory_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_DIR);
+}
+
+int dlm_recover_locks_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_LOCKS);
+}
+
+int dlm_recover_done_wait(struct dlm_ls *ls)
+{
+	return wait_status(ls, DLM_RS_DONE);
+}
+
+/*
+ * The recover_list contains all the rsb's for which we've requested the new
+ * master nodeid.  As replies are returned from the resource directories the
+ * rsb's are removed from the list.  When the list is empty we're done.
+ *
+ * The recover_list is later similarly used for all rsb's for which we've sent
+ * new lkb's and need to receive new corresponding lkid's.
+ *
+ * We use the address of the rsb struct as a simple local identifier for the
+ * rsb so we can match an rcom reply with the rsb it was sent for.
+ */
+
+static int recover_list_empty(struct dlm_ls *ls)
+{
+	int empty;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	empty = list_empty(&ls->ls_recover_list);
+	spin_unlock(&ls->ls_recover_list_lock);
+
+	return empty;
+}
+
+static void recover_list_add(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	if (list_empty(&r->res_recover_list)) {
+		list_add_tail(&r->res_recover_list, &ls->ls_recover_list);
+		ls->ls_recover_list_count++;
+		dlm_hold_rsb(r);
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+static void recover_list_del(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	list_del_init(&r->res_recover_list);
+	ls->ls_recover_list_count--;
+	spin_unlock(&ls->ls_recover_list_lock);
+
+	dlm_put_rsb(r);
+}
+
+static struct dlm_rsb *recover_list_find(struct dlm_ls *ls, uint64_t id)
+{
+	struct dlm_rsb *r = NULL;
+
+	spin_lock(&ls->ls_recover_list_lock);
+
+	list_for_each_entry(r, &ls->ls_recover_list, res_recover_list) {
+		if (id == (unsigned long) r)
+			goto out;
+	}
+	r = NULL;
+ out:
+	spin_unlock(&ls->ls_recover_list_lock);
+	return r;
+}
+
+static void recover_list_clear(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r, *s;
+
+	spin_lock(&ls->ls_recover_list_lock);
+	list_for_each_entry_safe(r, s, &ls->ls_recover_list, res_recover_list) {
+		list_del_init(&r->res_recover_list);
+		dlm_put_rsb(r);
+		ls->ls_recover_list_count--;
+	}
+
+	if (ls->ls_recover_list_count != 0) {
+		log_error(ls, "warning: recover_list_count %d",
+			  ls->ls_recover_list_count);
+		ls->ls_recover_list_count = 0;
+	}
+	spin_unlock(&ls->ls_recover_list_lock);
+}
+
+
+/* Master recovery: find new master node for rsb's that were
+   mastered on nodes that have been removed.
+
+   dlm_recover_masters
+   recover_master
+   dlm_send_rcom_lookup            ->  receive_rcom_lookup
+                                       dlm_dir_lookup
+   receive_rcom_lookup_reply       <-
+   dlm_recover_master_reply
+   set_new_master
+   set_master_lkbs
+   set_lock_master
+*/
+
+/*
+ * Set the lock master for all LKBs in a lock queue
+ * If we are the new master of the rsb, we may have received new
+ * MSTCPY locks from other nodes already which we need to ignore
+ * when setting the new nodeid.
+ */
+
+static void set_lock_master(struct list_head *queue, int nodeid)
+{
+	struct dlm_lkb *lkb;
+
+	list_for_each_entry(lkb, queue, lkb_statequeue)
+		if (!(lkb->lkb_flags & DLM_IFL_MSTCPY))
+			lkb->lkb_nodeid = nodeid;
+}
+
+static void set_master_lkbs(struct dlm_rsb *r)
+{
+	set_lock_master(&r->res_grantqueue, r->res_nodeid);
+	set_lock_master(&r->res_convertqueue, r->res_nodeid);
+	set_lock_master(&r->res_waitqueue, r->res_nodeid);
+}
+
+/*
+ * Propogate the new master nodeid to locks
+ * The NEW_MASTER flag tells dlm_recover_locks() which rsb's to consider.
+ * The NEW_MASTER2 flag tells recover_lvb() and set_locks_purged() which
+ * rsb's to consider.
+ */
+
+static void set_new_master(struct dlm_rsb *r, int nodeid)
+{
+	lock_rsb(r);
+	r->res_nodeid = nodeid;
+	set_master_lkbs(r);
+	rsb_set_flag(r, RSB_NEW_MASTER);
+	rsb_set_flag(r, RSB_NEW_MASTER2);
+	unlock_rsb(r);
+}
+
+/*
+ * We do async lookups on rsb's that need new masters.  The rsb's
+ * waiting for a lookup reply are kept on the recover_list.
+ */
+
+static int recover_master(struct dlm_rsb *r)
+{
+	struct dlm_ls *ls = r->res_ls;
+	int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+
+	dir_nodeid = dlm_dir_nodeid(r);
+
+	if (dir_nodeid == our_nodeid) {
+		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
+				       r->res_length, &ret_nodeid);
+		if (error)
+			log_error(ls, "recover dir lookup error %d", error);
+
+		if (ret_nodeid == our_nodeid)
+			ret_nodeid = 0;
+		set_new_master(r, ret_nodeid);
+	} else {
+		recover_list_add(r);
+		error = dlm_send_rcom_lookup(r, dir_nodeid);
+	}
+
+	return error;
+}
+
+/*
+ * When not using a directory, most resource names will hash to a new static
+ * master nodeid and the resource will need to be remastered.
+ */
+
+static int recover_master_static(struct dlm_rsb *r)
+{
+	int master = dlm_dir_nodeid(r);
+
+	if (master == dlm_our_nodeid())
+		master = 0;
+
+	if (r->res_nodeid != master) {
+		if (is_master(r))
+			dlm_purge_mstcpy_locks(r);
+		set_new_master(r, master);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Go through local root resources and for each rsb which has a master which
+ * has departed, get the new master nodeid from the directory.  The dir will
+ * assign mastery to the first node to look up the new master.  That means
+ * we'll discover in this lookup if we're the new master of any rsb's.
+ *
+ * We fire off all the dir lookup requests individually and asynchronously to
+ * the correct dir node.
+ */
+
+int dlm_recover_masters(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int error = 0, count = 0;
+
+	log_debug(ls, "dlm_recover_masters");
+
+	down_read(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		if (dlm_recovery_stopped(ls)) {
+			up_read(&ls->ls_root_sem);
+			error = -EINTR;
+			goto out;
+		}
+
+		if (dlm_no_directory(ls))
+			count += recover_master_static(r);
+		else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) {
+			recover_master(r);
+			count++;
+		}
+
+		schedule();
+	}
+	up_read(&ls->ls_root_sem);
+
+	log_debug(ls, "dlm_recover_masters %d resources", count);
+
+	error = dlm_wait_function(ls, &recover_list_empty);
+ out:
+	if (error)
+		recover_list_clear(ls);
+	return error;
+}
+
+int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+	struct dlm_rsb *r;
+	int nodeid;
+
+	r = recover_list_find(ls, rc->rc_id);
+	if (!r) {
+		log_error(ls, "dlm_recover_master_reply no id %llx",
+			  (unsigned long long)rc->rc_id);
+		goto out;
+	}
+
+	nodeid = rc->rc_result;
+	if (nodeid == dlm_our_nodeid())
+		nodeid = 0;
+
+	set_new_master(r, nodeid);
+	recover_list_del(r);
+
+	if (recover_list_empty(ls))
+		wake_up(&ls->ls_wait_general);
+ out:
+	return 0;
+}
+
+
+/* Lock recovery: rebuild the process-copy locks we hold on a
+   remastered rsb on the new rsb master.
+
+   dlm_recover_locks
+   recover_locks
+   recover_locks_queue
+   dlm_send_rcom_lock              ->  receive_rcom_lock
+                                       dlm_recover_master_copy
+   receive_rcom_lock_reply         <-
+   dlm_recover_process_copy
+*/
+
+
+/*
+ * keep a count of the number of lkb's we send to the new master; when we get
+ * an equal number of replies then recovery for the rsb is done
+ */
+
+static int recover_locks_queue(struct dlm_rsb *r, struct list_head *head)
+{
+	struct dlm_lkb *lkb;
+	int error = 0;
+
+	list_for_each_entry(lkb, head, lkb_statequeue) {
+	   	error = dlm_send_rcom_lock(r, lkb);
+		if (error)
+			break;
+		r->res_recover_locks_count++;
+	}
+
+	return error;
+}
+
+static int recover_locks(struct dlm_rsb *r)
+{
+	int error = 0;
+
+	lock_rsb(r);
+
+	DLM_ASSERT(!r->res_recover_locks_count, dlm_dump_rsb(r););
+
+	error = recover_locks_queue(r, &r->res_grantqueue);
+	if (error)
+		goto out;
+	error = recover_locks_queue(r, &r->res_convertqueue);
+	if (error)
+		goto out;
+	error = recover_locks_queue(r, &r->res_waitqueue);
+	if (error)
+		goto out;
+
+	if (r->res_recover_locks_count)
+		recover_list_add(r);
+	else
+		rsb_clear_flag(r, RSB_NEW_MASTER);
+ out:
+	unlock_rsb(r);
+	return error;
+}
+
+int dlm_recover_locks(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int error, count = 0;
+
+	log_debug(ls, "dlm_recover_locks");
+
+	down_read(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		if (is_master(r)) {
+			rsb_clear_flag(r, RSB_NEW_MASTER);
+			continue;
+		}
+
+		if (!rsb_flag(r, RSB_NEW_MASTER))
+			continue;
+
+		if (dlm_recovery_stopped(ls)) {
+			error = -EINTR;
+			up_read(&ls->ls_root_sem);
+			goto out;
+		}
+
+		error = recover_locks(r);
+		if (error) {
+			up_read(&ls->ls_root_sem);
+			goto out;
+		}
+
+		count += r->res_recover_locks_count;
+	}
+	up_read(&ls->ls_root_sem);
+
+	log_debug(ls, "dlm_recover_locks %d locks", count);
+
+	error = dlm_wait_function(ls, &recover_list_empty);
+ out:
+	if (error)
+		recover_list_clear(ls);
+	else
+		dlm_set_recover_status(ls, DLM_RS_LOCKS);
+	return error;
+}
+
+void dlm_recovered_lock(struct dlm_rsb *r)
+{
+	DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_dump_rsb(r););
+
+	r->res_recover_locks_count--;
+	if (!r->res_recover_locks_count) {
+		rsb_clear_flag(r, RSB_NEW_MASTER);
+		recover_list_del(r);
+	}
+
+	if (recover_list_empty(r->res_ls))
+		wake_up(&r->res_ls->ls_wait_general);
+}
+
+/*
+ * The lvb needs to be recovered on all master rsb's.  This includes setting
+ * the VALNOTVALID flag if necessary, and determining the correct lvb contents
+ * based on the lvb's of the locks held on the rsb.
+ *
+ * RSB_VALNOTVALID is set if there are only NL/CR locks on the rsb.  If it
+ * was already set prior to recovery, it's not cleared, regardless of locks.
+ *
+ * The LVB contents are only considered for changing when this is a new master
+ * of the rsb (NEW_MASTER2).  Then, the rsb's lvb is taken from any lkb with
+ * mode > CR.  If no lkb's exist with mode above CR, the lvb contents are taken
+ * from the lkb with the largest lvb sequence number.
+ */
+
+static void recover_lvb(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb, *high_lkb = NULL;
+	uint32_t high_seq = 0;
+	int lock_lvb_exists = 0;
+	int big_lock_exists = 0;
+	int lvblen = r->res_ls->ls_lvblen;
+
+	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			continue;
+
+		lock_lvb_exists = 1;
+
+		if (lkb->lkb_grmode > DLM_LOCK_CR) {
+			big_lock_exists = 1;
+			goto setflag;
+		}
+
+		if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
+			high_lkb = lkb;
+			high_seq = lkb->lkb_lvbseq;
+		}
+	}
+
+	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+		if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+			continue;
+
+		lock_lvb_exists = 1;
+
+		if (lkb->lkb_grmode > DLM_LOCK_CR) {
+			big_lock_exists = 1;
+			goto setflag;
+		}
+
+		if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
+			high_lkb = lkb;
+			high_seq = lkb->lkb_lvbseq;
+		}
+	}
+
+ setflag:
+	if (!lock_lvb_exists)
+		goto out;
+
+	if (!big_lock_exists)
+		rsb_set_flag(r, RSB_VALNOTVALID);
+
+	/* don't mess with the lvb unless we're the new master */
+	if (!rsb_flag(r, RSB_NEW_MASTER2))
+		goto out;
+
+	if (!r->res_lvbptr) {
+		r->res_lvbptr = allocate_lvb(r->res_ls);
+		if (!r->res_lvbptr)
+			goto out;
+	}
+
+	if (big_lock_exists) {
+		r->res_lvbseq = lkb->lkb_lvbseq;
+		memcpy(r->res_lvbptr, lkb->lkb_lvbptr, lvblen);
+	} else if (high_lkb) {
+		r->res_lvbseq = high_lkb->lkb_lvbseq;
+		memcpy(r->res_lvbptr, high_lkb->lkb_lvbptr, lvblen);
+	} else {
+		r->res_lvbseq = 0;
+		memset(r->res_lvbptr, 0, lvblen);
+	}
+ out:
+	return;
+}
+
+/* All master rsb's flagged RECOVER_CONVERT need to be looked at.  The locks
+   converting PR->CW or CW->PR need to have their lkb_grmode set. */
+
+static void recover_conversion(struct dlm_rsb *r)
+{
+	struct dlm_lkb *lkb;
+	int grmode = -1;
+
+	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+		if (lkb->lkb_grmode == DLM_LOCK_PR ||
+		    lkb->lkb_grmode == DLM_LOCK_CW) {
+			grmode = lkb->lkb_grmode;
+			break;
+		}
+	}
+
+	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+		if (lkb->lkb_grmode != DLM_LOCK_IV)
+			continue;
+		if (grmode == -1)
+			lkb->lkb_grmode = lkb->lkb_rqmode;
+		else
+			lkb->lkb_grmode = grmode;
+	}
+}
+
+/* We've become the new master for this rsb and waiting/converting locks may
+   need to be granted in dlm_grant_after_purge() due to locks that may have
+   existed from a removed node. */
+
+static void set_locks_purged(struct dlm_rsb *r)
+{
+	if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
+		rsb_set_flag(r, RSB_LOCKS_PURGED);
+}
+
+void dlm_recover_rsbs(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int count = 0;
+
+	log_debug(ls, "dlm_recover_rsbs");
+
+	down_read(&ls->ls_root_sem);
+	list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+		lock_rsb(r);
+		if (is_master(r)) {
+			if (rsb_flag(r, RSB_RECOVER_CONVERT))
+				recover_conversion(r);
+			if (rsb_flag(r, RSB_NEW_MASTER2))
+				set_locks_purged(r);
+			recover_lvb(r);
+			count++;
+		}
+		rsb_clear_flag(r, RSB_RECOVER_CONVERT);
+		rsb_clear_flag(r, RSB_NEW_MASTER2);
+		unlock_rsb(r);
+	}
+	up_read(&ls->ls_root_sem);
+
+	log_debug(ls, "dlm_recover_rsbs %d rsbs", count);
+}
+
+/* Create a single list of all root rsb's to be used during recovery */
+
+int dlm_create_root_list(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r;
+	int i, error = 0;
+
+	down_write(&ls->ls_root_sem);
+	if (!list_empty(&ls->ls_root_list)) {
+		log_error(ls, "root list not empty");
+		error = -EINVAL;
+		goto out;
+	}
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		read_lock(&ls->ls_rsbtbl[i].lock);
+		list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) {
+			list_add(&r->res_root_list, &ls->ls_root_list);
+			dlm_hold_rsb(r);
+		}
+		read_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+ out:
+	up_write(&ls->ls_root_sem);
+	return error;
+}
+
+void dlm_release_root_list(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r, *safe;
+
+	down_write(&ls->ls_root_sem);
+	list_for_each_entry_safe(r, safe, &ls->ls_root_list, res_root_list) {
+		list_del_init(&r->res_root_list);
+		dlm_put_rsb(r);
+	}
+	up_write(&ls->ls_root_sem);
+}
+
+void dlm_clear_toss_list(struct dlm_ls *ls)
+{
+	struct dlm_rsb *r, *safe;
+	int i;
+
+	for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+		write_lock(&ls->ls_rsbtbl[i].lock);
+		list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss,
+					 res_hashchain) {
+			list_del(&r->res_hashchain);
+			free_rsb(r);
+		}
+		write_unlock(&ls->ls_rsbtbl[i].lock);
+	}
+}
+
diff --git a/fs/dlm/recover.h b/fs/dlm/recover.h
new file mode 100644
index 0000000..ebd0363
--- /dev/null
+++ b/fs/dlm/recover.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RECOVER_DOT_H__
+#define __RECOVER_DOT_H__
+
+int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls));
+uint32_t dlm_recover_status(struct dlm_ls *ls);
+void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status);
+int dlm_recover_members_wait(struct dlm_ls *ls);
+int dlm_recover_directory_wait(struct dlm_ls *ls);
+int dlm_recover_locks_wait(struct dlm_ls *ls);
+int dlm_recover_done_wait(struct dlm_ls *ls);
+int dlm_recover_masters(struct dlm_ls *ls);
+int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc);
+int dlm_recover_locks(struct dlm_ls *ls);
+void dlm_recovered_lock(struct dlm_rsb *r);
+int dlm_create_root_list(struct dlm_ls *ls);
+void dlm_release_root_list(struct dlm_ls *ls);
+void dlm_clear_toss_list(struct dlm_ls *ls);
+void dlm_recover_rsbs(struct dlm_ls *ls);
+
+#endif				/* __RECOVER_DOT_H__ */
+
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
new file mode 100644
index 0000000..362e3ef
--- /dev/null
+++ b/fs/dlm/recoverd.c
@@ -0,0 +1,290 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "dir.h"
+#include "ast.h"
+#include "recover.h"
+#include "lowcomms.h"
+#include "lock.h"
+#include "requestqueue.h"
+#include "recoverd.h"
+
+
+/* If the start for which we're re-enabling locking (seq) has been superseded
+   by a newer stop (ls_recover_seq), we need to leave locking disabled. */
+
+static int enable_locking(struct dlm_ls *ls, uint64_t seq)
+{
+	int error = -EINTR;
+
+	spin_lock(&ls->ls_recover_lock);
+	if (ls->ls_recover_seq == seq) {
+		set_bit(LSFL_RUNNING, &ls->ls_flags);
+		up_write(&ls->ls_in_recovery);
+		error = 0;
+	}
+	spin_unlock(&ls->ls_recover_lock);
+	return error;
+}
+
+static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
+{
+	unsigned long start;
+	int error, neg = 0;
+
+	log_debug(ls, "recover %llx", rv->seq);
+
+	mutex_lock(&ls->ls_recoverd_active);
+
+	/*
+	 * Suspending and resuming dlm_astd ensures that no lkb's from this ls
+	 * will be processed by dlm_astd during recovery.
+	 */
+
+	dlm_astd_suspend();
+	dlm_astd_resume();
+
+	/*
+	 * This list of root rsb's will be the basis of most of the recovery
+	 * routines.
+	 */
+
+	dlm_create_root_list(ls);
+
+	/*
+	 * Free all the tossed rsb's so we don't have to recover them.
+	 */
+
+	dlm_clear_toss_list(ls);
+
+	/*
+	 * Add or remove nodes from the lockspace's ls_nodes list.
+	 * Also waits for all nodes to complete dlm_recover_members.
+	 */
+
+	error = dlm_recover_members(ls, rv, &neg);
+	if (error) {
+		log_error(ls, "recover_members failed %d", error);
+		goto fail;
+	}
+	start = jiffies;
+
+	/*
+	 * Rebuild our own share of the directory by collecting from all other
+	 * nodes their master rsb names that hash to us.
+	 */
+
+	error = dlm_recover_directory(ls);
+	if (error) {
+		log_error(ls, "recover_directory failed %d", error);
+		goto fail;
+	}
+
+	/*
+	 * Purge directory-related requests that are saved in requestqueue.
+	 * All dir requests from before recovery are invalid now due to the dir
+	 * rebuild and will be resent by the requesting nodes.
+	 */
+
+	dlm_purge_requestqueue(ls);
+
+	/*
+	 * Wait for all nodes to complete directory rebuild.
+	 */
+
+	error = dlm_recover_directory_wait(ls);
+	if (error) {
+		log_error(ls, "recover_directory_wait failed %d", error);
+		goto fail;
+	}
+
+	/*
+	 * We may have outstanding operations that are waiting for a reply from
+	 * a failed node.  Mark these to be resent after recovery.  Unlock and
+	 * cancel ops can just be completed.
+	 */
+
+	dlm_recover_waiters_pre(ls);
+
+	error = dlm_recovery_stopped(ls);
+	if (error)
+		goto fail;
+
+	if (neg || dlm_no_directory(ls)) {
+		/*
+		 * Clear lkb's for departed nodes.
+		 */
+
+		dlm_purge_locks(ls);
+
+		/*
+		 * Get new master nodeid's for rsb's that were mastered on
+		 * departed nodes.
+		 */
+
+		error = dlm_recover_masters(ls);
+		if (error) {
+			log_error(ls, "recover_masters failed %d", error);
+			goto fail;
+		}
+
+		/*
+		 * Send our locks on remastered rsb's to the new masters.
+		 */
+
+		error = dlm_recover_locks(ls);
+		if (error) {
+			log_error(ls, "recover_locks failed %d", error);
+			goto fail;
+		}
+
+		error = dlm_recover_locks_wait(ls);
+		if (error) {
+			log_error(ls, "recover_locks_wait failed %d", error);
+			goto fail;
+		}
+
+		/*
+		 * Finalize state in master rsb's now that all locks can be
+		 * checked.  This includes conversion resolution and lvb
+		 * settings.
+		 */
+
+		dlm_recover_rsbs(ls);
+	}
+
+	dlm_release_root_list(ls);
+
+	dlm_set_recover_status(ls, DLM_RS_DONE);
+	error = dlm_recover_done_wait(ls);
+	if (error) {
+		log_error(ls, "recover_done_wait failed %d", error);
+		goto fail;
+	}
+
+	dlm_clear_members_gone(ls);
+
+	error = enable_locking(ls, rv->seq);
+	if (error) {
+		log_error(ls, "enable_locking failed %d", error);
+		goto fail;
+	}
+
+	error = dlm_process_requestqueue(ls);
+	if (error) {
+		log_error(ls, "process_requestqueue failed %d", error);
+		goto fail;
+	}
+
+	error = dlm_recover_waiters_post(ls);
+	if (error) {
+		log_error(ls, "recover_waiters_post failed %d", error);
+		goto fail;
+	}
+
+	dlm_grant_after_purge(ls);
+
+	dlm_astd_wake();
+
+	log_debug(ls, "recover %llx done: %u ms", rv->seq,
+		  jiffies_to_msecs(jiffies - start));
+	mutex_unlock(&ls->ls_recoverd_active);
+
+	return 0;
+
+ fail:
+	dlm_release_root_list(ls);
+	log_debug(ls, "recover %llx error %d", rv->seq, error);
+	mutex_unlock(&ls->ls_recoverd_active);
+	return error;
+}
+
+static void do_ls_recovery(struct dlm_ls *ls)
+{
+	struct dlm_recover *rv = NULL;
+
+	spin_lock(&ls->ls_recover_lock);
+	rv = ls->ls_recover_args;
+	ls->ls_recover_args = NULL;
+	clear_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+	spin_unlock(&ls->ls_recover_lock);
+
+	if (rv) {
+		ls_recover(ls, rv);
+		kfree(rv->nodeids);
+		kfree(rv);
+	}
+}
+
+static int dlm_recoverd(void *arg)
+{
+	struct dlm_ls *ls;
+
+	ls = dlm_find_lockspace_local(arg);
+	if (!ls) {
+		log_print("dlm_recoverd: no lockspace %p", arg);
+		return -1;
+	}
+
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (!test_bit(LSFL_WORK, &ls->ls_flags))
+			schedule();
+		set_current_state(TASK_RUNNING);
+
+		if (test_and_clear_bit(LSFL_WORK, &ls->ls_flags))
+			do_ls_recovery(ls);
+	}
+
+	dlm_put_lockspace(ls);
+	return 0;
+}
+
+void dlm_recoverd_kick(struct dlm_ls *ls)
+{
+	set_bit(LSFL_WORK, &ls->ls_flags);
+	wake_up_process(ls->ls_recoverd_task);
+}
+
+int dlm_recoverd_start(struct dlm_ls *ls)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	p = kthread_run(dlm_recoverd, ls, "dlm_recoverd");
+	if (IS_ERR(p))
+		error = PTR_ERR(p);
+	else
+                ls->ls_recoverd_task = p;
+	return error;
+}
+
+void dlm_recoverd_stop(struct dlm_ls *ls)
+{
+	kthread_stop(ls->ls_recoverd_task);
+}
+
+void dlm_recoverd_suspend(struct dlm_ls *ls)
+{
+	wake_up(&ls->ls_wait_general);
+	mutex_lock(&ls->ls_recoverd_active);
+}
+
+void dlm_recoverd_resume(struct dlm_ls *ls)
+{
+	mutex_unlock(&ls->ls_recoverd_active);
+}
+
diff --git a/fs/dlm/recoverd.h b/fs/dlm/recoverd.h
new file mode 100644
index 0000000..866657c
--- /dev/null
+++ b/fs/dlm/recoverd.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RECOVERD_DOT_H__
+#define __RECOVERD_DOT_H__
+
+void dlm_recoverd_kick(struct dlm_ls *ls);
+void dlm_recoverd_stop(struct dlm_ls *ls);
+int dlm_recoverd_start(struct dlm_ls *ls);
+void dlm_recoverd_suspend(struct dlm_ls *ls);
+void dlm_recoverd_resume(struct dlm_ls *ls);
+
+#endif				/* __RECOVERD_DOT_H__ */
+
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
new file mode 100644
index 0000000..7b2b089
--- /dev/null
+++ b/fs/dlm/requestqueue.c
@@ -0,0 +1,184 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "member.h"
+#include "lock.h"
+#include "dir.h"
+#include "config.h"
+#include "requestqueue.h"
+
+struct rq_entry {
+	struct list_head list;
+	int nodeid;
+	char request[1];
+};
+
+/*
+ * Requests received while the lockspace is in recovery get added to the
+ * request queue and processed when recovery is complete.  This happens when
+ * the lockspace is suspended on some nodes before it is on others, or the
+ * lockspace is enabled on some while still suspended on others.
+ */
+
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
+{
+	struct rq_entry *e;
+	int length = hd->h_length;
+
+	if (dlm_is_removed(ls, nodeid))
+		return;
+
+	e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
+	if (!e) {
+		log_print("dlm_add_requestqueue: out of memory\n");
+		return;
+	}
+
+	e->nodeid = nodeid;
+	memcpy(e->request, hd, length);
+
+	mutex_lock(&ls->ls_requestqueue_mutex);
+	list_add_tail(&e->list, &ls->ls_requestqueue);
+	mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
+int dlm_process_requestqueue(struct dlm_ls *ls)
+{
+	struct rq_entry *e;
+	struct dlm_header *hd;
+	int error = 0;
+
+	mutex_lock(&ls->ls_requestqueue_mutex);
+
+	for (;;) {
+		if (list_empty(&ls->ls_requestqueue)) {
+			mutex_unlock(&ls->ls_requestqueue_mutex);
+			error = 0;
+			break;
+		}
+		e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
+		mutex_unlock(&ls->ls_requestqueue_mutex);
+
+		hd = (struct dlm_header *) e->request;
+		error = dlm_receive_message(hd, e->nodeid, 1);
+
+		if (error == -EINTR) {
+			/* entry is left on requestqueue */
+			log_debug(ls, "process_requestqueue abort eintr");
+			break;
+		}
+
+		mutex_lock(&ls->ls_requestqueue_mutex);
+		list_del(&e->list);
+		kfree(e);
+
+		if (dlm_locking_stopped(ls)) {
+			log_debug(ls, "process_requestqueue abort running");
+			mutex_unlock(&ls->ls_requestqueue_mutex);
+			error = -EINTR;
+			break;
+		}
+		schedule();
+	}
+
+	return error;
+}
+
+/*
+ * After recovery is done, locking is resumed and dlm_recoverd takes all the
+ * saved requests and processes them as they would have been by dlm_recvd.  At
+ * the same time, dlm_recvd will start receiving new requests from remote
+ * nodes.  We want to delay dlm_recvd processing new requests until
+ * dlm_recoverd has finished processing the old saved requests.
+ */
+
+void dlm_wait_requestqueue(struct dlm_ls *ls)
+{
+	for (;;) {
+		mutex_lock(&ls->ls_requestqueue_mutex);
+		if (list_empty(&ls->ls_requestqueue))
+			break;
+		if (dlm_locking_stopped(ls))
+			break;
+		mutex_unlock(&ls->ls_requestqueue_mutex);
+		schedule();
+	}
+	mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
+static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid)
+{
+	uint32_t type = ms->m_type;
+
+	if (dlm_is_removed(ls, nodeid))
+		return 1;
+
+	/* directory operations are always purged because the directory is
+	   always rebuilt during recovery and the lookups resent */
+
+	if (type == DLM_MSG_REMOVE ||
+	    type == DLM_MSG_LOOKUP ||
+	    type == DLM_MSG_LOOKUP_REPLY)
+		return 1;
+
+	if (!dlm_no_directory(ls))
+		return 0;
+
+	/* with no directory, the master is likely to change as a part of
+	   recovery; requests to/from the defunct master need to be purged */
+
+	switch (type) {
+	case DLM_MSG_REQUEST:
+	case DLM_MSG_CONVERT:
+	case DLM_MSG_UNLOCK:
+	case DLM_MSG_CANCEL:
+		/* we're no longer the master of this resource, the sender
+		   will resend to the new master (see waiter_needs_recovery) */
+
+		if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())
+			return 1;
+		break;
+
+	case DLM_MSG_REQUEST_REPLY:
+	case DLM_MSG_CONVERT_REPLY:
+	case DLM_MSG_UNLOCK_REPLY:
+	case DLM_MSG_CANCEL_REPLY:
+	case DLM_MSG_GRANT:
+		/* this reply is from the former master of the resource,
+		   we'll resend to the new master if needed */
+
+		if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)
+			return 1;
+		break;
+	}
+
+	return 0;
+}
+
+void dlm_purge_requestqueue(struct dlm_ls *ls)
+{
+	struct dlm_message *ms;
+	struct rq_entry *e, *safe;
+
+	mutex_lock(&ls->ls_requestqueue_mutex);
+	list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) {
+		ms = (struct dlm_message *) e->request;
+
+		if (purge_request(ls, ms, e->nodeid)) {
+			list_del(&e->list);
+			kfree(e);
+		}
+	}
+	mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h
new file mode 100644
index 0000000..349f0d2
--- /dev/null
+++ b/fs/dlm/requestqueue.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __REQUESTQUEUE_DOT_H__
+#define __REQUESTQUEUE_DOT_H__
+
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
+int dlm_process_requestqueue(struct dlm_ls *ls);
+void dlm_wait_requestqueue(struct dlm_ls *ls);
+void dlm_purge_requestqueue(struct dlm_ls *ls);
+
+#endif
+
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
new file mode 100644
index 0000000..c37e93e
--- /dev/null
+++ b/fs/dlm/user.c
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/dlm.h>
+#include <linux/dlm_device.h>
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "lock.h"
+#include "lvb_table.h"
+
+static const char *name_prefix="dlm";
+static struct miscdevice ctl_device;
+static struct file_operations device_fops;
+
+#ifdef CONFIG_COMPAT
+
+struct dlm_lock_params32 {
+	__u8 mode;
+	__u8 namelen;
+	__u16 flags;
+	__u32 lkid;
+	__u32 parent;
+
+	__u32 castparam;
+	__u32 castaddr;
+	__u32 bastparam;
+	__u32 bastaddr;
+	__u32 lksb;
+
+	char lvb[DLM_USER_LVB_LEN];
+	char name[0];
+};
+
+struct dlm_write_request32 {
+	__u32 version[3];
+	__u8 cmd;
+	__u8 is64bit;
+	__u8 unused[2];
+
+	union  {
+		struct dlm_lock_params32 lock;
+		struct dlm_lspace_params lspace;
+	} i;
+};
+
+struct dlm_lksb32 {
+	__u32 sb_status;
+	__u32 sb_lkid;
+	__u8 sb_flags;
+	__u32 sb_lvbptr;
+};
+
+struct dlm_lock_result32 {
+	__u32 length;
+	__u32 user_astaddr;
+	__u32 user_astparam;
+	__u32 user_lksb;
+	struct dlm_lksb32 lksb;
+	__u8 bast_mode;
+	__u8 unused[3];
+	/* Offsets may be zero if no data is present */
+	__u32 lvb_offset;
+};
+
+static void compat_input(struct dlm_write_request *kb,
+			 struct dlm_write_request32 *kb32)
+{
+	kb->version[0] = kb32->version[0];
+	kb->version[1] = kb32->version[1];
+	kb->version[2] = kb32->version[2];
+
+	kb->cmd = kb32->cmd;
+	kb->is64bit = kb32->is64bit;
+	if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
+	    kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
+		kb->i.lspace.flags = kb32->i.lspace.flags;
+		kb->i.lspace.minor = kb32->i.lspace.minor;
+		strcpy(kb->i.lspace.name, kb32->i.lspace.name);
+	} else {
+		kb->i.lock.mode = kb32->i.lock.mode;
+		kb->i.lock.namelen = kb32->i.lock.namelen;
+		kb->i.lock.flags = kb32->i.lock.flags;
+		kb->i.lock.lkid = kb32->i.lock.lkid;
+		kb->i.lock.parent = kb32->i.lock.parent;
+		kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;
+		kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;
+		kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;
+		kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
+		kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
+		memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
+		memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen);
+	}
+}
+
+static void compat_output(struct dlm_lock_result *res,
+			  struct dlm_lock_result32 *res32)
+{
+	res32->length = res->length - (sizeof(struct dlm_lock_result) -
+				       sizeof(struct dlm_lock_result32));
+	res32->user_astaddr = (__u32)(long)res->user_astaddr;
+	res32->user_astparam = (__u32)(long)res->user_astparam;
+	res32->user_lksb = (__u32)(long)res->user_lksb;
+	res32->bast_mode = res->bast_mode;
+
+	res32->lvb_offset = res->lvb_offset;
+	res32->length = res->length;
+
+	res32->lksb.sb_status = res->lksb.sb_status;
+	res32->lksb.sb_flags = res->lksb.sb_flags;
+	res32->lksb.sb_lkid = res->lksb.sb_lkid;
+	res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
+}
+#endif
+
+
+void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
+{
+	struct dlm_ls *ls;
+	struct dlm_user_args *ua;
+	struct dlm_user_proc *proc;
+	int remove_ownqueue = 0;
+
+	/* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
+	   lkb before dealing with it.  We need to check this
+	   flag before taking ls_clear_proc_locks mutex because if
+	   it's set, dlm_clear_proc_locks() holds the mutex. */
+
+	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
+		/* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */
+		return;
+	}
+
+	ls = lkb->lkb_resource->res_ls;
+	mutex_lock(&ls->ls_clear_proc_locks);
+
+	/* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
+	   can't be delivered.  For ORPHAN's, dlm_clear_proc_locks() freed
+	   lkb->ua so we can't try to use it. */
+
+	if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
+		/* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */
+		goto out;
+	}
+
+	DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
+	ua = (struct dlm_user_args *)lkb->lkb_astparam;
+	proc = ua->proc;
+
+	if (type == AST_BAST && ua->bastaddr == NULL)
+		goto out;
+
+	spin_lock(&proc->asts_spin);
+	if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+		kref_get(&lkb->lkb_ref);
+		list_add_tail(&lkb->lkb_astqueue, &proc->asts);
+		lkb->lkb_ast_type |= type;
+		wake_up_interruptible(&proc->wait);
+	}
+
+	/* noqueue requests that fail may need to be removed from the
+	   proc's locks list, there should be a better way of detecting
+	   this situation than checking all these things... */
+
+	if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV &&
+	    ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
+		remove_ownqueue = 1;
+
+	/* We want to copy the lvb to userspace when the completion
+	   ast is read if the status is 0, the lock has an lvb and
+	   lvb_ops says we should.  We could probably have set_lvb_lock()
+	   set update_user_lvb instead and not need old_mode */
+
+	if ((lkb->lkb_ast_type & AST_COMP) &&
+	    (lkb->lkb_lksb->sb_status == 0) &&
+	    lkb->lkb_lksb->sb_lvbptr &&
+	    dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])
+		ua->update_user_lvb = 1;
+	else
+		ua->update_user_lvb = 0;
+
+	spin_unlock(&proc->asts_spin);
+
+	if (remove_ownqueue) {
+		spin_lock(&ua->proc->locks_spin);
+		list_del_init(&lkb->lkb_ownqueue);
+		spin_unlock(&ua->proc->locks_spin);
+		dlm_put_lkb(lkb);
+	}
+ out:
+	mutex_unlock(&ls->ls_clear_proc_locks);
+}
+
+static int device_user_lock(struct dlm_user_proc *proc,
+			    struct dlm_lock_params *params)
+{
+	struct dlm_ls *ls;
+	struct dlm_user_args *ua;
+	int error = -ENOMEM;
+
+	ls = dlm_find_lockspace_local(proc->lockspace);
+	if (!ls)
+		return -ENOENT;
+
+	if (!params->castaddr || !params->lksb) {
+		error = -EINVAL;
+		goto out;
+	}
+
+	ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
+	if (!ua)
+		goto out;
+	ua->proc = proc;
+	ua->user_lksb = params->lksb;
+	ua->castparam = params->castparam;
+	ua->castaddr = params->castaddr;
+	ua->bastparam = params->bastparam;
+	ua->bastaddr = params->bastaddr;
+
+	if (params->flags & DLM_LKF_CONVERT)
+		error = dlm_user_convert(ls, ua,
+				         params->mode, params->flags,
+				         params->lkid, params->lvb);
+	else {
+		error = dlm_user_request(ls, ua,
+					 params->mode, params->flags,
+					 params->name, params->namelen,
+					 params->parent);
+		if (!error)
+			error = ua->lksb.sb_lkid;
+	}
+ out:
+	dlm_put_lockspace(ls);
+	return error;
+}
+
+static int device_user_unlock(struct dlm_user_proc *proc,
+			      struct dlm_lock_params *params)
+{
+	struct dlm_ls *ls;
+	struct dlm_user_args *ua;
+	int error = -ENOMEM;
+
+	ls = dlm_find_lockspace_local(proc->lockspace);
+	if (!ls)
+		return -ENOENT;
+
+	ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
+	if (!ua)
+		goto out;
+	ua->proc = proc;
+	ua->user_lksb = params->lksb;
+	ua->castparam = params->castparam;
+	ua->castaddr = params->castaddr;
+
+	if (params->flags & DLM_LKF_CANCEL)
+		error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
+	else
+		error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
+					params->lvb);
+ out:
+	dlm_put_lockspace(ls);
+	return error;
+}
+
+static int device_create_lockspace(struct dlm_lspace_params *params)
+{
+	dlm_lockspace_t *lockspace;
+	struct dlm_ls *ls;
+	int error, len;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	error = dlm_new_lockspace(params->name, strlen(params->name),
+				  &lockspace, 0, DLM_USER_LVB_LEN);
+	if (error)
+		return error;
+
+	ls = dlm_find_lockspace_local(lockspace);
+	if (!ls)
+		return -ENOENT;
+
+	error = -ENOMEM;
+	len = strlen(params->name) + strlen(name_prefix) + 2;
+	ls->ls_device.name = kzalloc(len, GFP_KERNEL);
+	if (!ls->ls_device.name)
+		goto fail;
+	snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
+		 params->name);
+	ls->ls_device.fops = &device_fops;
+	ls->ls_device.minor = MISC_DYNAMIC_MINOR;
+
+	error = misc_register(&ls->ls_device);
+	if (error) {
+		kfree(ls->ls_device.name);
+		goto fail;
+	}
+
+	error = ls->ls_device.minor;
+	dlm_put_lockspace(ls);
+	return error;
+
+ fail:
+	dlm_put_lockspace(ls);
+	dlm_release_lockspace(lockspace, 0);
+	return error;
+}
+
+static int device_remove_lockspace(struct dlm_lspace_params *params)
+{
+	dlm_lockspace_t *lockspace;
+	struct dlm_ls *ls;
+	int error, force = 0;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	ls = dlm_find_lockspace_device(params->minor);
+	if (!ls)
+		return -ENOENT;
+
+	error = misc_deregister(&ls->ls_device);
+	if (error) {
+		dlm_put_lockspace(ls);
+		goto out;
+	}
+	kfree(ls->ls_device.name);
+
+	if (params->flags & DLM_USER_LSFLG_FORCEFREE)
+		force = 2;
+
+	lockspace = ls->ls_local_handle;
+
+	/* dlm_release_lockspace waits for references to go to zero,
+	   so all processes will need to close their device for the ls
+	   before the release will procede */
+
+	dlm_put_lockspace(ls);
+	error = dlm_release_lockspace(lockspace, force);
+ out:
+	return error;
+}
+
+/* Check the user's version matches ours */
+static int check_version(struct dlm_write_request *req)
+{
+	if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
+	    (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
+	     req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
+
+		printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
+		       "user (%d.%d.%d) kernel (%d.%d.%d)\n",
+		       current->comm,
+		       current->pid,
+		       req->version[0],
+		       req->version[1],
+		       req->version[2],
+		       DLM_DEVICE_VERSION_MAJOR,
+		       DLM_DEVICE_VERSION_MINOR,
+		       DLM_DEVICE_VERSION_PATCH);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+/*
+ * device_write
+ *
+ *   device_user_lock
+ *     dlm_user_request -> request_lock
+ *     dlm_user_convert -> convert_lock
+ *
+ *   device_user_unlock
+ *     dlm_user_unlock -> unlock_lock
+ *     dlm_user_cancel -> cancel_lock
+ *
+ *   device_create_lockspace
+ *     dlm_new_lockspace
+ *
+ *   device_remove_lockspace
+ *     dlm_release_lockspace
+ */
+
+/* a write to a lockspace device is a lock or unlock request, a write
+   to the control device is to create/remove a lockspace */
+
+static ssize_t device_write(struct file *file, const char __user *buf,
+			    size_t count, loff_t *ppos)
+{
+	struct dlm_user_proc *proc = file->private_data;
+	struct dlm_write_request *kbuf;
+	sigset_t tmpsig, allsigs;
+	int error;
+
+#ifdef CONFIG_COMPAT
+	if (count < sizeof(struct dlm_write_request32))
+#else
+	if (count < sizeof(struct dlm_write_request))
+#endif
+		return -EINVAL;
+
+	kbuf = kmalloc(count, GFP_KERNEL);
+	if (!kbuf)
+		return -ENOMEM;
+
+	if (copy_from_user(kbuf, buf, count)) {
+		error = -EFAULT;
+		goto out_free;
+	}
+
+	if (check_version(kbuf)) {
+		error = -EBADE;
+		goto out_free;
+	}
+
+#ifdef CONFIG_COMPAT
+	if (!kbuf->is64bit) {
+		struct dlm_write_request32 *k32buf;
+		k32buf = (struct dlm_write_request32 *)kbuf;
+		kbuf = kmalloc(count + (sizeof(struct dlm_write_request) -
+			       sizeof(struct dlm_write_request32)), GFP_KERNEL);
+		if (!kbuf)
+			return -ENOMEM;
+
+		if (proc)
+			set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
+		compat_input(kbuf, k32buf);
+		kfree(k32buf);
+	}
+#endif
+
+	/* do we really need this? can a write happen after a close? */
+	if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
+	    test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
+		return -EINVAL;
+
+	sigfillset(&allsigs);
+	sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
+
+	error = -EINVAL;
+
+	switch (kbuf->cmd)
+	{
+	case DLM_USER_LOCK:
+		if (!proc) {
+			log_print("no locking on control device");
+			goto out_sig;
+		}
+		error = device_user_lock(proc, &kbuf->i.lock);
+		break;
+
+	case DLM_USER_UNLOCK:
+		if (!proc) {
+			log_print("no locking on control device");
+			goto out_sig;
+		}
+		error = device_user_unlock(proc, &kbuf->i.lock);
+		break;
+
+	case DLM_USER_CREATE_LOCKSPACE:
+		if (proc) {
+			log_print("create/remove only on control device");
+			goto out_sig;
+		}
+		error = device_create_lockspace(&kbuf->i.lspace);
+		break;
+
+	case DLM_USER_REMOVE_LOCKSPACE:
+		if (proc) {
+			log_print("create/remove only on control device");
+			goto out_sig;
+		}
+		error = device_remove_lockspace(&kbuf->i.lspace);
+		break;
+
+	default:
+		log_print("Unknown command passed to DLM device : %d\n",
+			  kbuf->cmd);
+	}
+
+ out_sig:
+	sigprocmask(SIG_SETMASK, &tmpsig, NULL);
+	recalc_sigpending();
+ out_free:
+	kfree(kbuf);
+	return error;
+}
+
+/* Every process that opens the lockspace device has its own "proc" structure
+   hanging off the open file that's used to keep track of locks owned by the
+   process and asts that need to be delivered to the process. */
+
+static int device_open(struct inode *inode, struct file *file)
+{
+	struct dlm_user_proc *proc;
+	struct dlm_ls *ls;
+
+	ls = dlm_find_lockspace_device(iminor(inode));
+	if (!ls)
+		return -ENOENT;
+
+	proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);
+	if (!proc) {
+		dlm_put_lockspace(ls);
+		return -ENOMEM;
+	}
+
+	proc->lockspace = ls->ls_local_handle;
+	INIT_LIST_HEAD(&proc->asts);
+	INIT_LIST_HEAD(&proc->locks);
+	spin_lock_init(&proc->asts_spin);
+	spin_lock_init(&proc->locks_spin);
+	init_waitqueue_head(&proc->wait);
+	file->private_data = proc;
+
+	return 0;
+}
+
+static int device_close(struct inode *inode, struct file *file)
+{
+	struct dlm_user_proc *proc = file->private_data;
+	struct dlm_ls *ls;
+	sigset_t tmpsig, allsigs;
+
+	ls = dlm_find_lockspace_local(proc->lockspace);
+	if (!ls)
+		return -ENOENT;
+
+	sigfillset(&allsigs);
+	sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
+
+	set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
+
+	dlm_clear_proc_locks(ls, proc);
+
+	/* at this point no more lkb's should exist for this lockspace,
+	   so there's no chance of dlm_user_add_ast() being called and
+	   looking for lkb->ua->proc */
+
+	kfree(proc);
+	file->private_data = NULL;
+
+	dlm_put_lockspace(ls);
+	dlm_put_lockspace(ls);  /* for the find in device_open() */
+
+	/* FIXME: AUTOFREE: if this ls is no longer used do
+	   device_remove_lockspace() */
+
+	sigprocmask(SIG_SETMASK, &tmpsig, NULL);
+	recalc_sigpending();
+
+	return 0;
+}
+
+static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
+			       int bmode, char __user *buf, size_t count)
+{
+#ifdef CONFIG_COMPAT
+	struct dlm_lock_result32 result32;
+#endif
+	struct dlm_lock_result result;
+	void *resultptr;
+	int error=0;
+	int len;
+	int struct_len;
+
+	memset(&result, 0, sizeof(struct dlm_lock_result));
+	memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb));
+	result.user_lksb = ua->user_lksb;
+
+	/* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
+	   in a conversion unless the conversion is successful.  See code
+	   in dlm_user_convert() for updating ua from ua_tmp.  OpenVMS, though,
+	   notes that a new blocking AST address and parameter are set even if
+	   the conversion fails, so maybe we should just do that. */
+
+	if (type == AST_BAST) {
+		result.user_astaddr = ua->bastaddr;
+		result.user_astparam = ua->bastparam;
+		result.bast_mode = bmode;
+	} else {
+		result.user_astaddr = ua->castaddr;
+		result.user_astparam = ua->castparam;
+	}
+
+#ifdef CONFIG_COMPAT
+	if (compat)
+		len = sizeof(struct dlm_lock_result32);
+	else
+#endif
+		len = sizeof(struct dlm_lock_result);
+	struct_len = len;
+
+	/* copy lvb to userspace if there is one, it's been updated, and
+	   the user buffer has space for it */
+
+	if (ua->update_user_lvb && ua->lksb.sb_lvbptr &&
+	    count >= len + DLM_USER_LVB_LEN) {
+		if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
+				 DLM_USER_LVB_LEN)) {
+			error = -EFAULT;
+			goto out;
+		}
+
+		result.lvb_offset = len;
+		len += DLM_USER_LVB_LEN;
+	}
+
+	result.length = len;
+	resultptr = &result;
+#ifdef CONFIG_COMPAT
+	if (compat) {
+		compat_output(&result, &result32);
+		resultptr = &result32;
+	}
+#endif
+
+	if (copy_to_user(buf, resultptr, struct_len))
+		error = -EFAULT;
+	else
+		error = len;
+ out:
+	return error;
+}
+
+/* a read returns a single ast described in a struct dlm_lock_result */
+
+static ssize_t device_read(struct file *file, char __user *buf, size_t count,
+			   loff_t *ppos)
+{
+	struct dlm_user_proc *proc = file->private_data;
+	struct dlm_lkb *lkb;
+	struct dlm_user_args *ua;
+	DECLARE_WAITQUEUE(wait, current);
+	int error, type=0, bmode=0, removed = 0;
+
+#ifdef CONFIG_COMPAT
+	if (count < sizeof(struct dlm_lock_result32))
+#else
+	if (count < sizeof(struct dlm_lock_result))
+#endif
+		return -EINVAL;
+
+	/* do we really need this? can a read happen after a close? */
+	if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
+		return -EINVAL;
+
+	spin_lock(&proc->asts_spin);
+	if (list_empty(&proc->asts)) {
+		if (file->f_flags & O_NONBLOCK) {
+			spin_unlock(&proc->asts_spin);
+			return -EAGAIN;
+		}
+
+		add_wait_queue(&proc->wait, &wait);
+
+	repeat:
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (list_empty(&proc->asts) && !signal_pending(current)) {
+			spin_unlock(&proc->asts_spin);
+			schedule();
+			spin_lock(&proc->asts_spin);
+			goto repeat;
+		}
+		set_current_state(TASK_RUNNING);
+		remove_wait_queue(&proc->wait, &wait);
+
+		if (signal_pending(current)) {
+			spin_unlock(&proc->asts_spin);
+			return -ERESTARTSYS;
+		}
+	}
+
+	if (list_empty(&proc->asts)) {
+		spin_unlock(&proc->asts_spin);
+		return -EAGAIN;
+	}
+
+	/* there may be both completion and blocking asts to return for
+	   the lkb, don't remove lkb from asts list unless no asts remain */
+
+	lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);
+
+	if (lkb->lkb_ast_type & AST_COMP) {
+		lkb->lkb_ast_type &= ~AST_COMP;
+		type = AST_COMP;
+	} else if (lkb->lkb_ast_type & AST_BAST) {
+		lkb->lkb_ast_type &= ~AST_BAST;
+		type = AST_BAST;
+		bmode = lkb->lkb_bastmode;
+	}
+
+	if (!lkb->lkb_ast_type) {
+		list_del(&lkb->lkb_astqueue);
+		removed = 1;
+	}
+	spin_unlock(&proc->asts_spin);
+
+	ua = (struct dlm_user_args *)lkb->lkb_astparam;
+	error = copy_result_to_user(ua,
+			 	test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
+				type, bmode, buf, count);
+
+	/* removes reference for the proc->asts lists added by
+	   dlm_user_add_ast() and may result in the lkb being freed */
+	if (removed)
+		dlm_put_lkb(lkb);
+
+	return error;
+}
+
+static unsigned int device_poll(struct file *file, poll_table *wait)
+{
+	struct dlm_user_proc *proc = file->private_data;
+
+	poll_wait(file, &proc->wait, wait);
+
+	spin_lock(&proc->asts_spin);
+	if (!list_empty(&proc->asts)) {
+		spin_unlock(&proc->asts_spin);
+		return POLLIN | POLLRDNORM;
+	}
+	spin_unlock(&proc->asts_spin);
+	return 0;
+}
+
+static int ctl_device_open(struct inode *inode, struct file *file)
+{
+	file->private_data = NULL;
+	return 0;
+}
+
+static int ctl_device_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations device_fops = {
+	.open    = device_open,
+	.release = device_close,
+	.read    = device_read,
+	.write   = device_write,
+	.poll    = device_poll,
+	.owner   = THIS_MODULE,
+};
+
+static struct file_operations ctl_device_fops = {
+	.open    = ctl_device_open,
+	.release = ctl_device_close,
+	.write   = device_write,
+	.owner   = THIS_MODULE,
+};
+
+int dlm_user_init(void)
+{
+	int error;
+
+	ctl_device.name = "dlm-control";
+	ctl_device.fops = &ctl_device_fops;
+	ctl_device.minor = MISC_DYNAMIC_MINOR;
+
+	error = misc_register(&ctl_device);
+	if (error)
+		log_print("misc_register failed for control device");
+
+	return error;
+}
+
+void dlm_user_exit(void)
+{
+	misc_deregister(&ctl_device);
+}
+
diff --git a/fs/dlm/user.h b/fs/dlm/user.h
new file mode 100644
index 0000000..d38e9f3
--- /dev/null
+++ b/fs/dlm/user.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __USER_DOT_H__
+#define __USER_DOT_H__
+
+void dlm_user_add_ast(struct dlm_lkb *lkb, int type);
+int dlm_user_init(void);
+void dlm_user_exit(void);
+
+#endif
diff --git a/fs/dlm/util.c b/fs/dlm/util.c
new file mode 100644
index 0000000..767197d
--- /dev/null
+++ b/fs/dlm/util.c
@@ -0,0 +1,161 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "rcom.h"
+#include "util.h"
+
+static void header_out(struct dlm_header *hd)
+{
+	hd->h_version		= cpu_to_le32(hd->h_version);
+	hd->h_lockspace		= cpu_to_le32(hd->h_lockspace);
+	hd->h_nodeid		= cpu_to_le32(hd->h_nodeid);
+	hd->h_length		= cpu_to_le16(hd->h_length);
+}
+
+static void header_in(struct dlm_header *hd)
+{
+	hd->h_version		= le32_to_cpu(hd->h_version);
+	hd->h_lockspace		= le32_to_cpu(hd->h_lockspace);
+	hd->h_nodeid		= le32_to_cpu(hd->h_nodeid);
+	hd->h_length		= le16_to_cpu(hd->h_length);
+}
+
+void dlm_message_out(struct dlm_message *ms)
+{
+	struct dlm_header *hd = (struct dlm_header *) ms;
+
+	header_out(hd);
+
+	ms->m_type		= cpu_to_le32(ms->m_type);
+	ms->m_nodeid		= cpu_to_le32(ms->m_nodeid);
+	ms->m_pid		= cpu_to_le32(ms->m_pid);
+	ms->m_lkid		= cpu_to_le32(ms->m_lkid);
+	ms->m_remid		= cpu_to_le32(ms->m_remid);
+	ms->m_parent_lkid	= cpu_to_le32(ms->m_parent_lkid);
+	ms->m_parent_remid	= cpu_to_le32(ms->m_parent_remid);
+	ms->m_exflags		= cpu_to_le32(ms->m_exflags);
+	ms->m_sbflags		= cpu_to_le32(ms->m_sbflags);
+	ms->m_flags		= cpu_to_le32(ms->m_flags);
+	ms->m_lvbseq		= cpu_to_le32(ms->m_lvbseq);
+	ms->m_hash		= cpu_to_le32(ms->m_hash);
+	ms->m_status		= cpu_to_le32(ms->m_status);
+	ms->m_grmode		= cpu_to_le32(ms->m_grmode);
+	ms->m_rqmode		= cpu_to_le32(ms->m_rqmode);
+	ms->m_bastmode		= cpu_to_le32(ms->m_bastmode);
+	ms->m_asts		= cpu_to_le32(ms->m_asts);
+	ms->m_result		= cpu_to_le32(ms->m_result);
+}
+
+void dlm_message_in(struct dlm_message *ms)
+{
+	struct dlm_header *hd = (struct dlm_header *) ms;
+
+	header_in(hd);
+
+	ms->m_type		= le32_to_cpu(ms->m_type);
+	ms->m_nodeid		= le32_to_cpu(ms->m_nodeid);
+	ms->m_pid		= le32_to_cpu(ms->m_pid);
+	ms->m_lkid		= le32_to_cpu(ms->m_lkid);
+	ms->m_remid		= le32_to_cpu(ms->m_remid);
+	ms->m_parent_lkid	= le32_to_cpu(ms->m_parent_lkid);
+	ms->m_parent_remid	= le32_to_cpu(ms->m_parent_remid);
+	ms->m_exflags		= le32_to_cpu(ms->m_exflags);
+	ms->m_sbflags		= le32_to_cpu(ms->m_sbflags);
+	ms->m_flags		= le32_to_cpu(ms->m_flags);
+	ms->m_lvbseq		= le32_to_cpu(ms->m_lvbseq);
+	ms->m_hash		= le32_to_cpu(ms->m_hash);
+	ms->m_status		= le32_to_cpu(ms->m_status);
+	ms->m_grmode		= le32_to_cpu(ms->m_grmode);
+	ms->m_rqmode		= le32_to_cpu(ms->m_rqmode);
+	ms->m_bastmode		= le32_to_cpu(ms->m_bastmode);
+	ms->m_asts		= le32_to_cpu(ms->m_asts);
+	ms->m_result		= le32_to_cpu(ms->m_result);
+}
+
+static void rcom_lock_out(struct rcom_lock *rl)
+{
+	rl->rl_ownpid		= cpu_to_le32(rl->rl_ownpid);
+	rl->rl_lkid		= cpu_to_le32(rl->rl_lkid);
+	rl->rl_remid		= cpu_to_le32(rl->rl_remid);
+	rl->rl_parent_lkid	= cpu_to_le32(rl->rl_parent_lkid);
+	rl->rl_parent_remid	= cpu_to_le32(rl->rl_parent_remid);
+	rl->rl_exflags		= cpu_to_le32(rl->rl_exflags);
+	rl->rl_flags		= cpu_to_le32(rl->rl_flags);
+	rl->rl_lvbseq		= cpu_to_le32(rl->rl_lvbseq);
+	rl->rl_result		= cpu_to_le32(rl->rl_result);
+	rl->rl_wait_type	= cpu_to_le16(rl->rl_wait_type);
+	rl->rl_namelen		= cpu_to_le16(rl->rl_namelen);
+}
+
+static void rcom_lock_in(struct rcom_lock *rl)
+{
+	rl->rl_ownpid		= le32_to_cpu(rl->rl_ownpid);
+	rl->rl_lkid		= le32_to_cpu(rl->rl_lkid);
+	rl->rl_remid		= le32_to_cpu(rl->rl_remid);
+	rl->rl_parent_lkid	= le32_to_cpu(rl->rl_parent_lkid);
+	rl->rl_parent_remid	= le32_to_cpu(rl->rl_parent_remid);
+	rl->rl_exflags		= le32_to_cpu(rl->rl_exflags);
+	rl->rl_flags		= le32_to_cpu(rl->rl_flags);
+	rl->rl_lvbseq		= le32_to_cpu(rl->rl_lvbseq);
+	rl->rl_result		= le32_to_cpu(rl->rl_result);
+	rl->rl_wait_type	= le16_to_cpu(rl->rl_wait_type);
+	rl->rl_namelen		= le16_to_cpu(rl->rl_namelen);
+}
+
+static void rcom_config_out(struct rcom_config *rf)
+{
+	rf->rf_lvblen		= cpu_to_le32(rf->rf_lvblen);
+	rf->rf_lsflags		= cpu_to_le32(rf->rf_lsflags);
+}
+
+static void rcom_config_in(struct rcom_config *rf)
+{
+	rf->rf_lvblen		= le32_to_cpu(rf->rf_lvblen);
+	rf->rf_lsflags		= le32_to_cpu(rf->rf_lsflags);
+}
+
+void dlm_rcom_out(struct dlm_rcom *rc)
+{
+	struct dlm_header *hd = (struct dlm_header *) rc;
+	int type = rc->rc_type;
+
+	header_out(hd);
+
+	rc->rc_type		= cpu_to_le32(rc->rc_type);
+	rc->rc_result		= cpu_to_le32(rc->rc_result);
+	rc->rc_id		= cpu_to_le64(rc->rc_id);
+
+	if (type == DLM_RCOM_LOCK)
+		rcom_lock_out((struct rcom_lock *) rc->rc_buf);
+
+	else if (type == DLM_RCOM_STATUS_REPLY)
+		rcom_config_out((struct rcom_config *) rc->rc_buf);
+}
+
+void dlm_rcom_in(struct dlm_rcom *rc)
+{
+	struct dlm_header *hd = (struct dlm_header *) rc;
+
+	header_in(hd);
+
+	rc->rc_type		= le32_to_cpu(rc->rc_type);
+	rc->rc_result		= le32_to_cpu(rc->rc_result);
+	rc->rc_id		= le64_to_cpu(rc->rc_id);
+
+	if (rc->rc_type == DLM_RCOM_LOCK)
+		rcom_lock_in((struct rcom_lock *) rc->rc_buf);
+
+	else if (rc->rc_type == DLM_RCOM_STATUS_REPLY)
+		rcom_config_in((struct rcom_config *) rc->rc_buf);
+}
+
diff --git a/fs/dlm/util.h b/fs/dlm/util.h
new file mode 100644
index 0000000..2b25915
--- /dev/null
+++ b/fs/dlm/util.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __UTIL_DOT_H__
+#define __UTIL_DOT_H__
+
+void dlm_message_out(struct dlm_message *ms);
+void dlm_message_in(struct dlm_message *ms);
+void dlm_rcom_out(struct dlm_rcom *rc);
+void dlm_rcom_in(struct dlm_rcom *rc);
+
+#endif
+
diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
new file mode 100644
index 0000000..ca65624
--- /dev/null
+++ b/fs/ecryptfs/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux 2.6 eCryptfs
+#
+
+obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
+
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o debug.o
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
new file mode 100644
index 0000000..ed35a9712
--- /dev/null
+++ b/fs/ecryptfs/crypto.c
@@ -0,0 +1,1659 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *   		Michael C. Thompson <mcthomps@us.ibm.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 <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/key.h>
+#include <linux/namei.h>
+#include <linux/crypto.h>
+#include <linux/file.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+static int
+ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+			     struct page *dst_page, int dst_offset,
+			     struct page *src_page, int src_offset, int size,
+			     unsigned char *iv);
+static int
+ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+			     struct page *dst_page, int dst_offset,
+			     struct page *src_page, int src_offset, int size,
+			     unsigned char *iv);
+
+/**
+ * ecryptfs_to_hex
+ * @dst: Buffer to take hex character representation of contents of
+ *       src; must be at least of size (src_size * 2)
+ * @src: Buffer to be converted to a hex string respresentation
+ * @src_size: number of bytes to convert
+ */
+void ecryptfs_to_hex(char *dst, char *src, size_t src_size)
+{
+	int x;
+
+	for (x = 0; x < src_size; x++)
+		sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);
+}
+
+/**
+ * ecryptfs_from_hex
+ * @dst: Buffer to take the bytes from src hex; must be at least of
+ *       size (src_size / 2)
+ * @src: Buffer to be converted from a hex string respresentation to raw value
+ * @dst_size: size of dst buffer, or number of hex characters pairs to convert
+ */
+void ecryptfs_from_hex(char *dst, char *src, int dst_size)
+{
+	int x;
+	char tmp[3] = { 0, };
+
+	for (x = 0; x < dst_size; x++) {
+		tmp[0] = src[x * 2];
+		tmp[1] = src[x * 2 + 1];
+		dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16);
+	}
+}
+
+/**
+ * ecryptfs_calculate_md5 - calculates the md5 of @src
+ * @dst: Pointer to 16 bytes of allocated memory
+ * @crypt_stat: Pointer to crypt_stat struct for the current inode
+ * @src: Data to be md5'd
+ * @len: Length of @src
+ *
+ * Uses the allocated crypto context that crypt_stat references to
+ * generate the MD5 sum of the contents of src.
+ */
+static int ecryptfs_calculate_md5(char *dst,
+				  struct ecryptfs_crypt_stat *crypt_stat,
+				  char *src, int len)
+{
+	int rc = 0;
+	struct scatterlist sg;
+
+	mutex_lock(&crypt_stat->cs_md5_tfm_mutex);
+	sg_init_one(&sg, (u8 *)src, len);
+	if (!crypt_stat->md5_tfm) {
+		crypt_stat->md5_tfm =
+			crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP);
+		if (!crypt_stat->md5_tfm) {
+			rc = -ENOMEM;
+			ecryptfs_printk(KERN_ERR, "Error attempting to "
+					"allocate crypto context\n");
+			goto out;
+		}
+	}
+	crypto_digest_init(crypt_stat->md5_tfm);
+	crypto_digest_update(crypt_stat->md5_tfm, &sg, 1);
+	crypto_digest_final(crypt_stat->md5_tfm, dst);
+	mutex_unlock(&crypt_stat->cs_md5_tfm_mutex);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_derive_iv
+ * @iv: destination for the derived iv vale
+ * @crypt_stat: Pointer to crypt_stat struct for the current inode
+ * @offset: Offset of the page whose's iv we are to derive
+ *
+ * Generate the initialization vector from the given root IV and page
+ * offset.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
+			      pgoff_t offset)
+{
+	int rc = 0;
+	char dst[MD5_DIGEST_SIZE];
+	char src[ECRYPTFS_MAX_IV_BYTES + 16];
+
+	if (unlikely(ecryptfs_verbosity > 0)) {
+		ecryptfs_printk(KERN_DEBUG, "root iv:\n");
+		ecryptfs_dump_hex(crypt_stat->root_iv, crypt_stat->iv_bytes);
+	}
+	/* TODO: It is probably secure to just cast the least
+	 * significant bits of the root IV into an unsigned long and
+	 * add the offset to that rather than go through all this
+	 * hashing business. -Halcrow */
+	memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);
+	memset((src + crypt_stat->iv_bytes), 0, 16);
+	snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset);
+	if (unlikely(ecryptfs_verbosity > 0)) {
+		ecryptfs_printk(KERN_DEBUG, "source:\n");
+		ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));
+	}
+	rc = ecryptfs_calculate_md5(dst, crypt_stat, src,
+				    (crypt_stat->iv_bytes + 16));
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
+				"MD5 while generating IV for a page\n");
+		goto out;
+	}
+	memcpy(iv, dst, crypt_stat->iv_bytes);
+	if (unlikely(ecryptfs_verbosity > 0)) {
+		ecryptfs_printk(KERN_DEBUG, "derived iv:\n");
+		ecryptfs_dump_hex(iv, crypt_stat->iv_bytes);
+	}
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_init_crypt_stat
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ *
+ * Initialize the crypt_stat structure.
+ */
+void
+ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
+	mutex_init(&crypt_stat->cs_mutex);
+	mutex_init(&crypt_stat->cs_tfm_mutex);
+	mutex_init(&crypt_stat->cs_md5_tfm_mutex);
+	ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_STRUCT_INITIALIZED);
+}
+
+/**
+ * ecryptfs_destruct_crypt_stat
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ *
+ * Releases all memory associated with a crypt_stat struct.
+ */
+void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	if (crypt_stat->tfm)
+		crypto_free_tfm(crypt_stat->tfm);
+	if (crypt_stat->md5_tfm)
+		crypto_free_tfm(crypt_stat->md5_tfm);
+	memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
+}
+
+void ecryptfs_destruct_mount_crypt_stat(
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
+{
+	if (mount_crypt_stat->global_auth_tok_key)
+		key_put(mount_crypt_stat->global_auth_tok_key);
+	if (mount_crypt_stat->global_key_tfm)
+		crypto_free_tfm(mount_crypt_stat->global_key_tfm);
+	memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));
+}
+
+/**
+ * virt_to_scatterlist
+ * @addr: Virtual address
+ * @size: Size of data; should be an even multiple of the block size
+ * @sg: Pointer to scatterlist array; set to NULL to obtain only
+ *      the number of scatterlist structs required in array
+ * @sg_size: Max array size
+ *
+ * Fills in a scatterlist array with page references for a passed
+ * virtual address.
+ *
+ * Returns the number of scatterlist structs in array used
+ */
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+			int sg_size)
+{
+	int i = 0;
+	struct page *pg;
+	int offset;
+	int remainder_of_page;
+
+	while (size > 0 && i < sg_size) {
+		pg = virt_to_page(addr);
+		offset = offset_in_page(addr);
+		if (sg) {
+			sg[i].page = pg;
+			sg[i].offset = offset;
+		}
+		remainder_of_page = PAGE_CACHE_SIZE - offset;
+		if (size >= remainder_of_page) {
+			if (sg)
+				sg[i].length = remainder_of_page;
+			addr += remainder_of_page;
+			size -= remainder_of_page;
+		} else {
+			if (sg)
+				sg[i].length = size;
+			addr += size;
+			size = 0;
+		}
+		i++;
+	}
+	if (size > 0)
+		return -ENOMEM;
+	return i;
+}
+
+/**
+ * encrypt_scatterlist
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ * @dest_sg: Destination of encrypted data
+ * @src_sg: Data to be encrypted
+ * @size: Length of data to be encrypted
+ * @iv: iv to use during encryption
+ *
+ * Returns the number of bytes encrypted; negative value on error
+ */
+static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
+			       struct scatterlist *dest_sg,
+			       struct scatterlist *src_sg, int size,
+			       unsigned char *iv)
+{
+	int rc = 0;
+
+	BUG_ON(!crypt_stat || !crypt_stat->tfm
+	       || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+				       ECRYPTFS_STRUCT_INITIALIZED));
+	if (unlikely(ecryptfs_verbosity > 0)) {
+		ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n",
+				crypt_stat->key_size);
+		ecryptfs_dump_hex(crypt_stat->key,
+				  crypt_stat->key_size);
+	}
+	/* Consider doing this once, when the file is opened */
+	mutex_lock(&crypt_stat->cs_tfm_mutex);
+	rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
+				  crypt_stat->key_size);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
+				rc);
+		mutex_unlock(&crypt_stat->cs_tfm_mutex);
+		rc = -EINVAL;
+		goto out;
+	}
+	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
+	crypto_cipher_encrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size, iv);
+	mutex_unlock(&crypt_stat->cs_tfm_mutex);
+out:
+	return rc;
+}
+
+static void
+ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx,
+					 int *byte_offset,
+					 struct ecryptfs_crypt_stat *crypt_stat,
+					 unsigned long extent_num)
+{
+	unsigned long lower_extent_num;
+	int extents_occupied_by_headers_at_front;
+	int bytes_occupied_by_headers_at_front;
+	int extent_offset;
+	int extents_per_page;
+
+	bytes_occupied_by_headers_at_front =
+		( crypt_stat->header_extent_size
+		  * crypt_stat->num_header_extents_at_front );
+	extents_occupied_by_headers_at_front =
+		( bytes_occupied_by_headers_at_front
+		  / crypt_stat->extent_size );
+	lower_extent_num = extents_occupied_by_headers_at_front + extent_num;
+	extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+	(*lower_page_idx) = lower_extent_num / extents_per_page;
+	extent_offset = lower_extent_num % extents_per_page;
+	(*byte_offset) = extent_offset * crypt_stat->extent_size;
+	ecryptfs_printk(KERN_DEBUG, " * crypt_stat->header_extent_size = "
+			"[%d]\n", crypt_stat->header_extent_size);
+	ecryptfs_printk(KERN_DEBUG, " * crypt_stat->"
+			"num_header_extents_at_front = [%d]\n",
+			crypt_stat->num_header_extents_at_front);
+	ecryptfs_printk(KERN_DEBUG, " * extents_occupied_by_headers_at_"
+			"front = [%d]\n", extents_occupied_by_headers_at_front);
+	ecryptfs_printk(KERN_DEBUG, " * lower_extent_num = [0x%.16x]\n",
+			lower_extent_num);
+	ecryptfs_printk(KERN_DEBUG, " * extents_per_page = [%d]\n",
+			extents_per_page);
+	ecryptfs_printk(KERN_DEBUG, " * (*lower_page_idx) = [0x%.16x]\n",
+			(*lower_page_idx));
+	ecryptfs_printk(KERN_DEBUG, " * extent_offset = [%d]\n",
+			extent_offset);
+	ecryptfs_printk(KERN_DEBUG, " * (*byte_offset) = [%d]\n",
+			(*byte_offset));
+}
+
+static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx,
+				   struct page *lower_page,
+				   struct inode *lower_inode,
+				   int byte_offset_in_page, int bytes_to_write)
+{
+	int rc = 0;
+
+	if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
+		rc = ecryptfs_commit_lower_page(lower_page, lower_inode,
+						ctx->param.lower_file,
+						byte_offset_in_page,
+						bytes_to_write);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error calling lower "
+					"commit; rc = [%d]\n", rc);
+			goto out;
+		}
+	} else {
+		rc = ecryptfs_writepage_and_release_lower_page(lower_page,
+							       lower_inode,
+							       ctx->param.wbc);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error calling lower "
+					"writepage(); rc = [%d]\n", rc);
+			goto out;
+		}
+	}
+out:
+	return rc;
+}
+
+static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx,
+				 struct page **lower_page,
+				 struct inode *lower_inode,
+				 unsigned long lower_page_idx,
+				 int byte_offset_in_page)
+{
+	int rc = 0;
+
+	if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
+		/* TODO: Limit this to only the data extents that are
+		 * needed */
+		rc = ecryptfs_get_lower_page(lower_page, lower_inode,
+					     ctx->param.lower_file,
+					     lower_page_idx,
+					     byte_offset_in_page,
+					     (PAGE_CACHE_SIZE
+					      - byte_offset_in_page));
+		if (rc) {
+			ecryptfs_printk(
+				KERN_ERR, "Error attempting to grab, map, "
+				"and prepare_write lower page with index "
+				"[0x%.16x]; rc = [%d]\n", lower_page_idx, rc);
+			goto out;
+		}
+	} else {
+		rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL,
+						      lower_inode,
+						      lower_page_idx);
+		if (rc) {
+			ecryptfs_printk(
+				KERN_ERR, "Error attempting to grab and map "
+				"lower page with index [0x%.16x]; rc = [%d]\n",
+				lower_page_idx, rc);
+			goto out;
+		}
+	}
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_encrypt_page
+ * @ctx: The context of the page
+ *
+ * Encrypt an eCryptfs page. This is done on a per-extent basis. Note
+ * that eCryptfs pages may straddle the lower pages -- for instance,
+ * if the file was created on a machine with an 8K page size
+ * (resulting in an 8K header), and then the file is copied onto a
+ * host with a 32K page size, then when reading page 0 of the eCryptfs
+ * file, 24K of page 0 of the lower file will be read and decrypted,
+ * and then 8K of page 1 of the lower file will be read and decrypted.
+ *
+ * The actual operations performed on each page depends on the
+ * contents of the ecryptfs_page_crypt_context struct.
+ *
+ * Returns zero on success; negative on error
+ */
+int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx)
+{
+	char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+	unsigned long base_extent;
+	unsigned long extent_offset = 0;
+	unsigned long lower_page_idx = 0;
+	unsigned long prior_lower_page_idx = 0;
+	struct page *lower_page;
+	struct inode *lower_inode;
+	struct ecryptfs_inode_info *inode_info;
+	struct ecryptfs_crypt_stat *crypt_stat;
+	int rc = 0;
+	int lower_byte_offset = 0;
+	int orig_byte_offset = 0;
+	int num_extents_per_page;
+#define ECRYPTFS_PAGE_STATE_UNREAD    0
+#define ECRYPTFS_PAGE_STATE_READ      1
+#define ECRYPTFS_PAGE_STATE_MODIFIED  2
+#define ECRYPTFS_PAGE_STATE_WRITTEN   3
+	int page_state;
+
+	lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host);
+	inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host);
+	crypt_stat = &inode_info->crypt_stat;
+	if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
+		rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode,
+						 ctx->param.lower_file);
+		if (rc)
+			ecryptfs_printk(KERN_ERR, "Error attempting to copy "
+					"page at index [0x%.16x]\n",
+					ctx->page->index);
+		goto out;
+	}
+	num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+	base_extent = (ctx->page->index * num_extents_per_page);
+	page_state = ECRYPTFS_PAGE_STATE_UNREAD;
+	while (extent_offset < num_extents_per_page) {
+		ecryptfs_extent_to_lwr_pg_idx_and_offset(
+			&lower_page_idx, &lower_byte_offset, crypt_stat,
+			(base_extent + extent_offset));
+		if (prior_lower_page_idx != lower_page_idx
+		    && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) {
+			rc = ecryptfs_write_out_page(ctx, lower_page,
+						     lower_inode,
+						     orig_byte_offset,
+						     (PAGE_CACHE_SIZE
+						      - orig_byte_offset));
+			if (rc) {
+				ecryptfs_printk(KERN_ERR, "Error attempting "
+						"to write out page; rc = [%d]"
+						"\n", rc);
+				goto out;
+			}
+			page_state = ECRYPTFS_PAGE_STATE_WRITTEN;
+		}
+		if (page_state == ECRYPTFS_PAGE_STATE_UNREAD
+		    || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) {
+			rc = ecryptfs_read_in_page(ctx, &lower_page,
+						   lower_inode, lower_page_idx,
+						   lower_byte_offset);
+			if (rc) {
+				ecryptfs_printk(KERN_ERR, "Error attempting "
+						"to read in lower page with "
+						"index [0x%.16x]; rc = [%d]\n",
+						lower_page_idx, rc);
+				goto out;
+			}
+			orig_byte_offset = lower_byte_offset;
+			prior_lower_page_idx = lower_page_idx;
+			page_state = ECRYPTFS_PAGE_STATE_READ;
+		}
+		BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED
+			 || page_state == ECRYPTFS_PAGE_STATE_READ));
+		rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+					(base_extent + extent_offset));
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error attempting to "
+					"derive IV for extent [0x%.16x]; "
+					"rc = [%d]\n",
+					(base_extent + extent_offset), rc);
+			goto out;
+		}
+		if (unlikely(ecryptfs_verbosity > 0)) {
+			ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
+					"with iv:\n");
+			ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+			ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+					"encryption:\n");
+			ecryptfs_dump_hex((char *)
+					  (page_address(ctx->page)
+					   + (extent_offset
+					      * crypt_stat->extent_size)), 8);
+		}
+		rc = ecryptfs_encrypt_page_offset(
+			crypt_stat, lower_page, lower_byte_offset, ctx->page,
+			(extent_offset * crypt_stat->extent_size),
+			crypt_stat->extent_size, extent_iv);
+		ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
+				"rc = [%d]\n",
+				(base_extent + extent_offset), rc);
+		if (unlikely(ecryptfs_verbosity > 0)) {
+			ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+					"encryption:\n");
+			ecryptfs_dump_hex((char *)(page_address(lower_page)
+						   + lower_byte_offset), 8);
+		}
+		page_state = ECRYPTFS_PAGE_STATE_MODIFIED;
+		extent_offset++;
+	}
+	BUG_ON(orig_byte_offset != 0);
+	rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0,
+				     (lower_byte_offset
+				      + crypt_stat->extent_size));
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error attempting to write out "
+				"page; rc = [%d]\n", rc);
+				goto out;
+	}
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_decrypt_page
+ * @file: The ecryptfs file
+ * @page: The page in ecryptfs to decrypt
+ *
+ * Decrypt an eCryptfs page. This is done on a per-extent basis. Note
+ * that eCryptfs pages may straddle the lower pages -- for instance,
+ * if the file was created on a machine with an 8K page size
+ * (resulting in an 8K header), and then the file is copied onto a
+ * host with a 32K page size, then when reading page 0 of the eCryptfs
+ * file, 24K of page 0 of the lower file will be read and decrypted,
+ * and then 8K of page 1 of the lower file will be read and decrypted.
+ *
+ * Returns zero on success; negative on error
+ */
+int ecryptfs_decrypt_page(struct file *file, struct page *page)
+{
+	char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+	unsigned long base_extent;
+	unsigned long extent_offset = 0;
+	unsigned long lower_page_idx = 0;
+	unsigned long prior_lower_page_idx = 0;
+	struct page *lower_page;
+	char *lower_page_virt = NULL;
+	struct inode *lower_inode;
+	struct ecryptfs_crypt_stat *crypt_stat;
+	int rc = 0;
+	int byte_offset;
+	int num_extents_per_page;
+	int page_state;
+
+	crypt_stat = &(ecryptfs_inode_to_private(
+			       page->mapping->host)->crypt_stat);
+	lower_inode = ecryptfs_inode_to_lower(page->mapping->host);
+	if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
+		rc = ecryptfs_do_readpage(file, page, page->index);
+		if (rc)
+			ecryptfs_printk(KERN_ERR, "Error attempting to copy "
+					"page at index [0x%.16x]\n",
+					page->index);
+		goto out;
+	}
+	num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+	base_extent = (page->index * num_extents_per_page);
+	lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache,
+					   SLAB_KERNEL);
+	if (!lower_page_virt) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR, "Error getting page for encrypted "
+				"lower page(s)\n");
+		goto out;
+	}
+	lower_page = virt_to_page(lower_page_virt);
+	page_state = ECRYPTFS_PAGE_STATE_UNREAD;
+	while (extent_offset < num_extents_per_page) {
+		ecryptfs_extent_to_lwr_pg_idx_and_offset(
+			&lower_page_idx, &byte_offset, crypt_stat,
+			(base_extent + extent_offset));
+		if (prior_lower_page_idx != lower_page_idx
+		    || page_state == ECRYPTFS_PAGE_STATE_UNREAD) {
+			rc = ecryptfs_do_readpage(file, lower_page,
+						  lower_page_idx);
+			if (rc) {
+				ecryptfs_printk(KERN_ERR, "Error reading "
+						"lower encrypted page; rc = "
+						"[%d]\n", rc);
+				goto out;
+			}
+			prior_lower_page_idx = lower_page_idx;
+			page_state = ECRYPTFS_PAGE_STATE_READ;
+		}
+		rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+					(base_extent + extent_offset));
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error attempting to "
+					"derive IV for extent [0x%.16x]; rc = "
+					"[%d]\n",
+					(base_extent + extent_offset), rc);
+			goto out;
+		}
+		if (unlikely(ecryptfs_verbosity > 0)) {
+			ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
+					"with iv:\n");
+			ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+			ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+					"decryption:\n");
+			ecryptfs_dump_hex((lower_page_virt + byte_offset), 8);
+		}
+		rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
+						  (extent_offset
+						   * crypt_stat->extent_size),
+						  lower_page, byte_offset,
+						  crypt_stat->extent_size,
+						  extent_iv);
+		if (rc != crypt_stat->extent_size) {
+			ecryptfs_printk(KERN_ERR, "Error attempting to "
+					"decrypt extent [0x%.16x]\n",
+					(base_extent + extent_offset));
+			goto out;
+		}
+		rc = 0;
+		if (unlikely(ecryptfs_verbosity > 0)) {
+			ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+					"decryption:\n");
+			ecryptfs_dump_hex((char *)(page_address(page)
+						   + byte_offset), 8);
+		}
+		extent_offset++;
+	}
+out:
+	if (lower_page_virt)
+		kmem_cache_free(ecryptfs_lower_page_cache, lower_page_virt);
+	return rc;
+}
+
+/**
+ * decrypt_scatterlist
+ *
+ * Returns the number of bytes decrypted; negative value on error
+ */
+static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
+			       struct scatterlist *dest_sg,
+			       struct scatterlist *src_sg, int size,
+			       unsigned char *iv)
+{
+	int rc = 0;
+
+	/* Consider doing this once, when the file is opened */
+	mutex_lock(&crypt_stat->cs_tfm_mutex);
+	rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
+				  crypt_stat->key_size);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
+				rc);
+		mutex_unlock(&crypt_stat->cs_tfm_mutex);
+		rc = -EINVAL;
+		goto out;
+	}
+	ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
+	rc = crypto_cipher_decrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size,
+				      iv);
+	mutex_unlock(&crypt_stat->cs_tfm_mutex);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n",
+				rc);
+		goto out;
+	}
+	rc = size;
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_encrypt_page_offset
+ *
+ * Returns the number of bytes encrypted
+ */
+static int
+ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+			     struct page *dst_page, int dst_offset,
+			     struct page *src_page, int src_offset, int size,
+			     unsigned char *iv)
+{
+	struct scatterlist src_sg, dst_sg;
+
+	src_sg.page = src_page;
+	src_sg.offset = src_offset;
+	src_sg.length = size;
+	dst_sg.page = dst_page;
+	dst_sg.offset = dst_offset;
+	dst_sg.length = size;
+	return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
+}
+
+/**
+ * ecryptfs_decrypt_page_offset
+ *
+ * Returns the number of bytes decrypted
+ */
+static int
+ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+			     struct page *dst_page, int dst_offset,
+			     struct page *src_page, int src_offset, int size,
+			     unsigned char *iv)
+{
+	struct scatterlist src_sg, dst_sg;
+
+	src_sg.page = src_page;
+	src_sg.offset = src_offset;
+	src_sg.length = size;
+	dst_sg.page = dst_page;
+	dst_sg.offset = dst_offset;
+	dst_sg.length = size;
+	return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
+}
+
+#define ECRYPTFS_MAX_SCATTERLIST_LEN 4
+
+/**
+ * ecryptfs_init_crypt_ctx
+ * @crypt_stat: Uninitilized crypt stats structure
+ *
+ * Initialize the crypto context.
+ *
+ * TODO: Performance: Keep a cache of initialized cipher contexts;
+ * only init if needed
+ */
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	int rc = -EINVAL;
+
+	if (!crypt_stat->cipher) {
+		ecryptfs_printk(KERN_ERR, "No cipher specified\n");
+		goto out;
+	}
+	ecryptfs_printk(KERN_DEBUG,
+			"Initializing cipher [%s]; strlen = [%d]; "
+			"key_size_bits = [%d]\n",
+			crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
+			crypt_stat->key_size << 3);
+	if (crypt_stat->tfm) {
+		rc = 0;
+		goto out;
+	}
+	mutex_lock(&crypt_stat->cs_tfm_mutex);
+	crypt_stat->tfm = crypto_alloc_tfm(crypt_stat->cipher,
+					   ECRYPTFS_DEFAULT_CHAINING_MODE
+					   | CRYPTO_TFM_REQ_WEAK_KEY);
+	mutex_unlock(&crypt_stat->cs_tfm_mutex);
+	if (!crypt_stat->tfm) {
+		ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): "
+				"Error initializing cipher [%s]\n",
+				crypt_stat->cipher);
+		goto out;
+	}
+	rc = 0;
+out:
+	return rc;
+}
+
+static void set_extent_mask_and_shift(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	int extent_size_tmp;
+
+	crypt_stat->extent_mask = 0xFFFFFFFF;
+	crypt_stat->extent_shift = 0;
+	if (crypt_stat->extent_size == 0)
+		return;
+	extent_size_tmp = crypt_stat->extent_size;
+	while ((extent_size_tmp & 0x01) == 0) {
+		extent_size_tmp >>= 1;
+		crypt_stat->extent_mask <<= 1;
+		crypt_stat->extent_shift++;
+	}
+}
+
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	/* Default values; may be overwritten as we are parsing the
+	 * packets. */
+	crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;
+	set_extent_mask_and_shift(crypt_stat);
+	crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
+	if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+		crypt_stat->header_extent_size =
+			ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
+	} else
+		crypt_stat->header_extent_size = PAGE_CACHE_SIZE;
+	crypt_stat->num_header_extents_at_front = 1;
+}
+
+/**
+ * ecryptfs_compute_root_iv
+ * @crypt_stats
+ *
+ * On error, sets the root IV to all 0's.
+ */
+int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	int rc = 0;
+	char dst[MD5_DIGEST_SIZE];
+
+	BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE);
+	BUG_ON(crypt_stat->iv_bytes <= 0);
+	if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_WARNING, "Session key not valid; "
+				"cannot generate root IV\n");
+		goto out;
+	}
+	rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key,
+				    crypt_stat->key_size);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
+				"MD5 while generating root IV\n");
+		goto out;
+	}
+	memcpy(crypt_stat->root_iv, dst, crypt_stat->iv_bytes);
+out:
+	if (rc) {
+		memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes);
+		ECRYPTFS_SET_FLAG(crypt_stat->flags,
+				  ECRYPTFS_SECURITY_WARNING);
+	}
+	return rc;
+}
+
+static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	get_random_bytes(crypt_stat->key, crypt_stat->key_size);
+	ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+	ecryptfs_compute_root_iv(crypt_stat);
+	if (unlikely(ecryptfs_verbosity > 0)) {
+		ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n");
+		ecryptfs_dump_hex(crypt_stat->key,
+				  crypt_stat->key_size);
+	}
+}
+
+/**
+ * ecryptfs_set_default_crypt_stat_vals
+ * @crypt_stat
+ *
+ * Default values in the event that policy does not override them.
+ */
+static void ecryptfs_set_default_crypt_stat_vals(
+	struct ecryptfs_crypt_stat *crypt_stat,
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
+{
+	ecryptfs_set_default_sizes(crypt_stat);
+	strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER);
+	crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES;
+	ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+	crypt_stat->file_version = ECRYPTFS_FILE_VERSION;
+	crypt_stat->mount_crypt_stat = mount_crypt_stat;
+}
+
+/**
+ * ecryptfs_new_file_context
+ * @ecryptfs_dentry
+ *
+ * If the crypto context for the file has not yet been established,
+ * this is where we do that.  Establishing a new crypto context
+ * involves the following decisions:
+ *  - What cipher to use?
+ *  - What set of authentication tokens to use?
+ * Here we just worry about getting enough information into the
+ * authentication tokens so that we know that they are available.
+ * We associate the available authentication tokens with the new file
+ * via the set of signatures in the crypt_stat struct.  Later, when
+ * the headers are actually written out, we may again defer to
+ * userspace to perform the encryption of the session key; for the
+ * foreseeable future, this will be the case with public key packets.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+/* Associate an authentication token(s) with the file */
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry)
+{
+	int rc = 0;
+	struct ecryptfs_crypt_stat *crypt_stat =
+	    &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+	    &ecryptfs_superblock_to_private(
+		    ecryptfs_dentry->d_sb)->mount_crypt_stat;
+	int cipher_name_len;
+
+	ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat);
+	/* See if there are mount crypt options */
+	if (mount_crypt_stat->global_auth_tok) {
+		ecryptfs_printk(KERN_DEBUG, "Initializing context for new "
+				"file using mount_crypt_stat\n");
+		ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+		ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+		memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++],
+		       mount_crypt_stat->global_auth_tok_sig,
+		       ECRYPTFS_SIG_SIZE_HEX);
+		cipher_name_len =
+		    strlen(mount_crypt_stat->global_default_cipher_name);
+		memcpy(crypt_stat->cipher,
+		       mount_crypt_stat->global_default_cipher_name,
+		       cipher_name_len);
+		crypt_stat->cipher[cipher_name_len] = '\0';
+		crypt_stat->key_size =
+			mount_crypt_stat->global_default_cipher_key_size;
+		ecryptfs_generate_new_key(crypt_stat);
+	} else
+		/* We should not encounter this scenario since we
+		 * should detect lack of global_auth_tok at mount time
+		 * TODO: Applies to 0.1 release only; remove in future
+		 * release */
+		BUG();
+	rc = ecryptfs_init_crypt_ctx(crypt_stat);
+	if (rc)
+		ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "
+				"context for cipher [%s]: rc = [%d]\n",
+				crypt_stat->cipher, rc);
+	return rc;
+}
+
+/**
+ * contains_ecryptfs_marker - check for the ecryptfs marker
+ * @data: The data block in which to check
+ *
+ * Returns one if marker found; zero if not found
+ */
+int contains_ecryptfs_marker(char *data)
+{
+	u32 m_1, m_2;
+
+	memcpy(&m_1, data, 4);
+	m_1 = be32_to_cpu(m_1);
+	memcpy(&m_2, (data + 4), 4);
+	m_2 = be32_to_cpu(m_2);
+	if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2)
+		return 1;
+	ecryptfs_printk(KERN_DEBUG, "m_1 = [0x%.8x]; m_2 = [0x%.8x]; "
+			"MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n", m_1, m_2,
+			MAGIC_ECRYPTFS_MARKER);
+	ecryptfs_printk(KERN_DEBUG, "(m_1 ^ MAGIC_ECRYPTFS_MARKER) = "
+			"[0x%.8x]\n", (m_1 ^ MAGIC_ECRYPTFS_MARKER));
+	return 0;
+}
+
+struct ecryptfs_flag_map_elem {
+	u32 file_flag;
+	u32 local_flag;
+};
+
+/* Add support for additional flags by adding elements here. */
+static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = {
+	{0x00000001, ECRYPTFS_ENABLE_HMAC},
+	{0x00000002, ECRYPTFS_ENCRYPTED}
+};
+
+/**
+ * ecryptfs_process_flags
+ * @crypt_stat
+ * @page_virt: Source data to be parsed
+ * @bytes_read: Updated with the number of bytes read
+ *
+ * Returns zero on success; non-zero if the flag set is invalid
+ */
+static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat,
+				  char *page_virt, int *bytes_read)
+{
+	int rc = 0;
+	int i;
+	u32 flags;
+
+	memcpy(&flags, page_virt, 4);
+	flags = be32_to_cpu(flags);
+	for (i = 0; i < ((sizeof(ecryptfs_flag_map)
+			  / sizeof(struct ecryptfs_flag_map_elem))); i++)
+		if (flags & ecryptfs_flag_map[i].file_flag) {
+			ECRYPTFS_SET_FLAG(crypt_stat->flags,
+					  ecryptfs_flag_map[i].local_flag);
+		} else
+			ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
+					    ecryptfs_flag_map[i].local_flag);
+	/* Version is in top 8 bits of the 32-bit flag vector */
+	crypt_stat->file_version = ((flags >> 24) & 0xFF);
+	(*bytes_read) = 4;
+	return rc;
+}
+
+/**
+ * write_ecryptfs_marker
+ * @page_virt: The pointer to in a page to begin writing the marker
+ * @written: Number of bytes written
+ *
+ * Marker = 0x3c81b7f5
+ */
+static void write_ecryptfs_marker(char *page_virt, size_t *written)
+{
+	u32 m_1, m_2;
+
+	get_random_bytes(&m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+	m_2 = (m_1 ^ MAGIC_ECRYPTFS_MARKER);
+	m_1 = cpu_to_be32(m_1);
+	memcpy(page_virt, &m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+	m_2 = cpu_to_be32(m_2);
+	memcpy(page_virt + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2), &m_2,
+	       (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+	(*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+}
+
+static void
+write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
+		     size_t *written)
+{
+	u32 flags = 0;
+	int i;
+
+	for (i = 0; i < ((sizeof(ecryptfs_flag_map)
+			  / sizeof(struct ecryptfs_flag_map_elem))); i++)
+		if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+					ecryptfs_flag_map[i].local_flag))
+			flags |= ecryptfs_flag_map[i].file_flag;
+	/* Version is in top 8 bits of the 32-bit flag vector */
+	flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000);
+	flags = cpu_to_be32(flags);
+	memcpy(page_virt, &flags, 4);
+	(*written) = 4;
+}
+
+struct ecryptfs_cipher_code_str_map_elem {
+	char cipher_str[16];
+	u16 cipher_code;
+};
+
+/* Add support for additional ciphers by adding elements here. The
+ * cipher_code is whatever OpenPGP applicatoins use to identify the
+ * ciphers. List in order of probability. */
+static struct ecryptfs_cipher_code_str_map_elem
+ecryptfs_cipher_code_str_map[] = {
+	{"aes",RFC2440_CIPHER_AES_128 },
+	{"blowfish", RFC2440_CIPHER_BLOWFISH},
+	{"des3_ede", RFC2440_CIPHER_DES3_EDE},
+	{"cast5", RFC2440_CIPHER_CAST_5},
+	{"twofish", RFC2440_CIPHER_TWOFISH},
+	{"cast6", RFC2440_CIPHER_CAST_6},
+	{"aes", RFC2440_CIPHER_AES_192},
+	{"aes", RFC2440_CIPHER_AES_256}
+};
+
+/**
+ * ecryptfs_code_for_cipher_string
+ * @str: The string representing the cipher name
+ *
+ * Returns zero on no match, or the cipher code on match
+ */
+u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	int i;
+	u16 code = 0;
+	struct ecryptfs_cipher_code_str_map_elem *map =
+		ecryptfs_cipher_code_str_map;
+
+	if (strcmp(crypt_stat->cipher, "aes") == 0) {
+		switch (crypt_stat->key_size) {
+		case 16:
+			code = RFC2440_CIPHER_AES_128;
+			break;
+		case 24:
+			code = RFC2440_CIPHER_AES_192;
+			break;
+		case 32:
+			code = RFC2440_CIPHER_AES_256;
+		}
+	} else {
+		for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
+			if (strcmp(crypt_stat->cipher, map[i].cipher_str) == 0){
+				code = map[i].cipher_code;
+				break;
+			}
+	}
+	return code;
+}
+
+/**
+ * ecryptfs_cipher_code_to_string
+ * @str: Destination to write out the cipher name
+ * @cipher_code: The code to convert to cipher name string
+ *
+ * Returns zero on success
+ */
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
+{
+	int rc = 0;
+	int i;
+
+	str[0] = '\0';
+	for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
+		if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code)
+			strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str);
+	if (str[0] == '\0') {
+		ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: "
+				"[%d]\n", cipher_code);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+/**
+ * ecryptfs_read_header_region
+ * @data
+ * @dentry
+ * @nd
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+				struct vfsmount *mnt)
+{
+	struct file *file;
+	mm_segment_t oldfs;
+	int rc;
+
+	mnt = mntget(mnt);
+	file = dentry_open(dentry, mnt, O_RDONLY);
+	if (IS_ERR(file)) {
+		ecryptfs_printk(KERN_DEBUG, "Error opening file to "
+				"read header region\n");
+		mntput(mnt);
+		rc = PTR_ERR(file);
+		goto out;
+	}
+	file->f_pos = 0;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	/* For releases 0.1 and 0.2, all of the header information
+	 * fits in the first data extent-sized region. */
+	rc = file->f_op->read(file, (char __user *)data,
+			      ECRYPTFS_DEFAULT_EXTENT_SIZE, &file->f_pos);
+	set_fs(oldfs);
+	fput(file);
+	rc = 0;
+out:
+	return rc;
+}
+
+static void
+write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat,
+		      size_t *written)
+{
+	u32 header_extent_size;
+	u16 num_header_extents_at_front;
+
+	header_extent_size = (u32)crypt_stat->header_extent_size;
+	num_header_extents_at_front =
+		(u16)crypt_stat->num_header_extents_at_front;
+	header_extent_size = cpu_to_be32(header_extent_size);
+	memcpy(virt, &header_extent_size, 4);
+	virt += 4;
+	num_header_extents_at_front = cpu_to_be16(num_header_extents_at_front);
+	memcpy(virt, &num_header_extents_at_front, 2);
+	(*written) = 6;
+}
+
+struct kmem_cache *ecryptfs_header_cache_0;
+struct kmem_cache *ecryptfs_header_cache_1;
+struct kmem_cache *ecryptfs_header_cache_2;
+
+/**
+ * ecryptfs_write_headers_virt
+ * @page_virt
+ * @crypt_stat
+ * @ecryptfs_dentry
+ *
+ * Format version: 1
+ *
+ *   Header Extent:
+ *     Octets 0-7:        Unencrypted file size (big-endian)
+ *     Octets 8-15:       eCryptfs special marker
+ *     Octets 16-19:      Flags
+ *      Octet 16:         File format version number (between 0 and 255)
+ *      Octets 17-18:     Reserved
+ *      Octet 19:         Bit 1 (lsb): Reserved
+ *                        Bit 2: Encrypted?
+ *                        Bits 3-8: Reserved
+ *     Octets 20-23:      Header extent size (big-endian)
+ *     Octets 24-25:      Number of header extents at front of file
+ *                        (big-endian)
+ *     Octet  26:         Begin RFC 2440 authentication token packet set
+ *   Data Extent 0:
+ *     Lower data (CBC encrypted)
+ *   Data Extent 1:
+ *     Lower data (CBC encrypted)
+ *   ...
+ *
+ * Returns zero on success
+ */
+int ecryptfs_write_headers_virt(char *page_virt,
+				struct ecryptfs_crypt_stat *crypt_stat,
+				struct dentry *ecryptfs_dentry)
+{
+	int rc;
+	size_t written;
+	size_t offset;
+
+	offset = ECRYPTFS_FILE_SIZE_BYTES;
+	write_ecryptfs_marker((page_virt + offset), &written);
+	offset += written;
+	write_ecryptfs_flags((page_virt + offset), crypt_stat, &written);
+	offset += written;
+	write_header_metadata((page_virt + offset), crypt_stat, &written);
+	offset += written;
+	rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat,
+					      ecryptfs_dentry, &written,
+					      PAGE_CACHE_SIZE - offset);
+	if (rc)
+		ecryptfs_printk(KERN_WARNING, "Error generating key packet "
+				"set; rc = [%d]\n", rc);
+	return rc;
+}
+
+/**
+ * ecryptfs_write_headers
+ * @lower_file: The lower file struct, which was returned from dentry_open
+ *
+ * Write the file headers out.  This will likely involve a userspace
+ * callout, in which the session key is encrypted with one or more
+ * public keys and/or the passphrase necessary to do the encryption is
+ * retrieved via a prompt.  Exactly what happens at this point should
+ * be policy-dependent.
+ *
+ * Returns zero on success; non-zero on error
+ */
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+			   struct file *lower_file)
+{
+	mm_segment_t oldfs;
+	struct ecryptfs_crypt_stat *crypt_stat;
+	char *page_virt;
+	int current_header_page;
+	int header_pages;
+	int rc = 0;
+
+	crypt_stat = &ecryptfs_inode_to_private(
+		ecryptfs_dentry->d_inode)->crypt_stat;
+	if (likely(ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+				       ECRYPTFS_ENCRYPTED))) {
+		if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+					 ECRYPTFS_KEY_VALID)) {
+			ecryptfs_printk(KERN_DEBUG, "Key is "
+					"invalid; bailing out\n");
+			rc = -EINVAL;
+			goto out;
+		}
+	} else {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_WARNING,
+				"Called with crypt_stat->encrypted == 0\n");
+		goto out;
+	}
+	/* Released in this function */
+	page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER);
+	if (!page_virt) {
+		ecryptfs_printk(KERN_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(page_virt, 0, PAGE_CACHE_SIZE);
+	rc = ecryptfs_write_headers_virt(page_virt, crypt_stat,
+					 ecryptfs_dentry);
+	if (unlikely(rc)) {
+		ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
+		memset(page_virt, 0, PAGE_CACHE_SIZE);
+		goto out_free;
+	}
+	ecryptfs_printk(KERN_DEBUG,
+			"Writing key packet set to underlying file\n");
+	lower_file->f_pos = 0;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
+			"write() w/ header page; lower_file->f_pos = "
+			"[0x%.16x]\n", lower_file->f_pos);
+	lower_file->f_op->write(lower_file, (char __user *)page_virt,
+				PAGE_CACHE_SIZE, &lower_file->f_pos);
+	header_pages = ((crypt_stat->header_extent_size
+			 * crypt_stat->num_header_extents_at_front)
+			/ PAGE_CACHE_SIZE);
+	memset(page_virt, 0, PAGE_CACHE_SIZE);
+	current_header_page = 1;
+	while (current_header_page < header_pages) {
+		ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
+				"write() w/ zero'd page; lower_file->f_pos = "
+				"[0x%.16x]\n", lower_file->f_pos);
+		lower_file->f_op->write(lower_file, (char __user *)page_virt,
+					PAGE_CACHE_SIZE, &lower_file->f_pos);
+		current_header_page++;
+	}
+	set_fs(oldfs);
+	ecryptfs_printk(KERN_DEBUG,
+			"Done writing key packet set to underlying file.\n");
+out_free:
+	kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+out:
+	return rc;
+}
+
+static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
+				 char *virt, int *bytes_read)
+{
+	int rc = 0;
+	u32 header_extent_size;
+	u16 num_header_extents_at_front;
+
+	memcpy(&header_extent_size, virt, 4);
+	header_extent_size = be32_to_cpu(header_extent_size);
+	virt += 4;
+	memcpy(&num_header_extents_at_front, virt, 2);
+	num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
+	crypt_stat->header_extent_size = (int)header_extent_size;
+	crypt_stat->num_header_extents_at_front =
+		(int)num_header_extents_at_front;
+	(*bytes_read) = 6;
+	if ((crypt_stat->header_extent_size
+	     * crypt_stat->num_header_extents_at_front)
+	    < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_WARNING, "Invalid header extent size: "
+				"[%d]\n", crypt_stat->header_extent_size);
+	}
+	return rc;
+}
+
+/**
+ * set_default_header_data
+ *
+ * For version 0 file format; this function is only for backwards
+ * compatibility for files created with the prior versions of
+ * eCryptfs.
+ */
+static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
+{
+	crypt_stat->header_extent_size = 4096;
+	crypt_stat->num_header_extents_at_front = 1;
+}
+
+/**
+ * ecryptfs_read_headers_virt
+ *
+ * Read/parse the header data. The header format is detailed in the
+ * comment block for the ecryptfs_write_headers_virt() function.
+ *
+ * Returns zero on success
+ */
+static int ecryptfs_read_headers_virt(char *page_virt,
+				      struct ecryptfs_crypt_stat *crypt_stat,
+				      struct dentry *ecryptfs_dentry)
+{
+	int rc = 0;
+	int offset;
+	int bytes_read;
+
+	ecryptfs_set_default_sizes(crypt_stat);
+	crypt_stat->mount_crypt_stat = &ecryptfs_superblock_to_private(
+		ecryptfs_dentry->d_sb)->mount_crypt_stat;
+	offset = ECRYPTFS_FILE_SIZE_BYTES;
+	rc = contains_ecryptfs_marker(page_virt + offset);
+	if (rc == 0) {
+		rc = -EINVAL;
+		goto out;
+	}
+	offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+	rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),
+				    &bytes_read);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "Error processing flags\n");
+		goto out;
+	}
+	if (crypt_stat->file_version > ECRYPTFS_SUPPORTED_FILE_VERSION) {
+		ecryptfs_printk(KERN_WARNING, "File version is [%d]; only "
+				"file version [%d] is supported by this "
+				"version of eCryptfs\n",
+				crypt_stat->file_version,
+				ECRYPTFS_SUPPORTED_FILE_VERSION);
+		rc = -EINVAL;
+		goto out;
+	}
+	offset += bytes_read;
+	if (crypt_stat->file_version >= 1) {
+		rc = parse_header_metadata(crypt_stat, (page_virt + offset),
+					   &bytes_read);
+		if (rc) {
+			ecryptfs_printk(KERN_WARNING, "Error reading header "
+					"metadata; rc = [%d]\n", rc);
+		}
+		offset += bytes_read;
+	} else
+		set_default_header_data(crypt_stat);
+	rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset),
+				       ecryptfs_dentry);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_read_headers
+ *
+ * Returns zero if valid headers found and parsed; non-zero otherwise
+ */
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+			  struct file *lower_file)
+{
+	int rc = 0;
+	char *page_virt = NULL;
+	mm_segment_t oldfs;
+	ssize_t bytes_read;
+	struct ecryptfs_crypt_stat *crypt_stat =
+	    &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
+
+	/* Read the first page from the underlying file */
+	page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, SLAB_USER);
+	if (!page_virt) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n");
+		goto out;
+	}
+	lower_file->f_pos = 0;
+	oldfs = get_fs();
+	set_fs(get_ds());
+	bytes_read = lower_file->f_op->read(lower_file,
+					    (char __user *)page_virt,
+					    ECRYPTFS_DEFAULT_EXTENT_SIZE,
+					    &lower_file->f_pos);
+	set_fs(oldfs);
+	if (bytes_read != ECRYPTFS_DEFAULT_EXTENT_SIZE) {
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,
+					ecryptfs_dentry);
+	if (rc) {
+		ecryptfs_printk(KERN_DEBUG, "Valid eCryptfs headers not "
+				"found\n");
+		rc = -EINVAL;
+	}
+out:
+	if (page_virt) {
+		memset(page_virt, 0, PAGE_CACHE_SIZE);
+		kmem_cache_free(ecryptfs_header_cache_1, page_virt);
+	}
+	return rc;
+}
+
+/**
+ * ecryptfs_encode_filename - converts a plaintext file name to cipher text
+ * @crypt_stat: The crypt_stat struct associated with the file anem to encode
+ * @name: The plaintext name
+ * @length: The length of the plaintext
+ * @encoded_name: The encypted name
+ *
+ * Encrypts and encodes a filename into something that constitutes a
+ * valid filename for a filesystem, with printable characters.
+ *
+ * We assume that we have a properly initialized crypto context,
+ * pointed to by crypt_stat->tfm.
+ *
+ * TODO: Implement filename decoding and decryption here, in place of
+ * memcpy. We are keeping the framework around for now to (1)
+ * facilitate testing of the components needed to implement filename
+ * encryption and (2) to provide a code base from which other
+ * developers in the community can easily implement this feature.
+ *
+ * Returns the length of encoded filename; negative if error
+ */
+int
+ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+			 const char *name, int length, char **encoded_name)
+{
+	int error = 0;
+
+	(*encoded_name) = kmalloc(length + 2, GFP_KERNEL);
+	if (!(*encoded_name)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	/* TODO: Filename encryption is a scheduled feature for a
+	 * future version of eCryptfs. This function is here only for
+	 * the purpose of providing a framework for other developers
+	 * to easily implement filename encryption. Hint: Replace this
+	 * memcpy() with a call to encrypt and encode the
+	 * filename, the set the length accordingly. */
+	memcpy((void *)(*encoded_name), (void *)name, length);
+	(*encoded_name)[length] = '\0';
+	error = length + 1;
+out:
+	return error;
+}
+
+/**
+ * ecryptfs_decode_filename - converts the cipher text name to plaintext
+ * @crypt_stat: The crypt_stat struct associated with the file
+ * @name: The filename in cipher text
+ * @length: The length of the cipher text name
+ * @decrypted_name: The plaintext name
+ *
+ * Decodes and decrypts the filename.
+ *
+ * We assume that we have a properly initialized crypto context,
+ * pointed to by crypt_stat->tfm.
+ *
+ * TODO: Implement filename decoding and decryption here, in place of
+ * memcpy. We are keeping the framework around for now to (1)
+ * facilitate testing of the components needed to implement filename
+ * encryption and (2) to provide a code base from which other
+ * developers in the community can easily implement this feature.
+ *
+ * Returns the length of decoded filename; negative if error
+ */
+int
+ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+			 const char *name, int length, char **decrypted_name)
+{
+	int error = 0;
+
+	(*decrypted_name) = kmalloc(length + 2, GFP_KERNEL);
+	if (!(*decrypted_name)) {
+		error = -ENOMEM;
+		goto out;
+	}
+	/* TODO: Filename encryption is a scheduled feature for a
+	 * future version of eCryptfs. This function is here only for
+	 * the purpose of providing a framework for other developers
+	 * to easily implement filename encryption. Hint: Replace this
+	 * memcpy() with a call to decode and decrypt the
+	 * filename, the set the length accordingly. */
+	memcpy((void *)(*decrypted_name), (void *)name, length);
+	(*decrypted_name)[length + 1] = '\0';	/* Only for convenience
+						 * in printing out the
+						 * string in debug
+						 * messages */
+	error = length;
+out:
+	return error;
+}
+
+/**
+ * ecryptfs_process_cipher - Perform cipher initialization.
+ * @tfm: Crypto context set by this function
+ * @key_tfm: Crypto context for key material, set by this function
+ * @cipher_name: Name of the cipher.
+ * @key_size: Size of the key in bytes.
+ *
+ * Returns zero on success. Any crypto_tfm structs allocated here
+ * should be released by other functions, such as on a superblock put
+ * event, regardless of whether this function succeeds for fails.
+ */
+int
+ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm,
+			char *cipher_name, size_t key_size)
+{
+	char dummy_key[ECRYPTFS_MAX_KEY_BYTES];
+	int rc;
+
+	*tfm = *key_tfm = NULL;
+	if (key_size > ECRYPTFS_MAX_KEY_BYTES) {
+		rc = -EINVAL;
+		printk(KERN_ERR "Requested key size is [%Zd] bytes; maximum "
+		       "allowable is [%d]\n", key_size, ECRYPTFS_MAX_KEY_BYTES);
+		goto out;
+	}
+	*tfm = crypto_alloc_tfm(cipher_name, (ECRYPTFS_DEFAULT_CHAINING_MODE
+					      | CRYPTO_TFM_REQ_WEAK_KEY));
+	if (!(*tfm)) {
+		rc = -EINVAL;
+		printk(KERN_ERR "Unable to allocate crypto cipher with name "
+		       "[%s]\n", cipher_name);
+		goto out;
+	}
+	*key_tfm = crypto_alloc_tfm(cipher_name, CRYPTO_TFM_REQ_WEAK_KEY);
+	if (!(*key_tfm)) {
+		rc = -EINVAL;
+		printk(KERN_ERR "Unable to allocate crypto cipher with name "
+		       "[%s]\n", cipher_name);
+		goto out;
+	}
+	if (key_size < crypto_tfm_alg_min_keysize(*tfm)) {
+		rc = -EINVAL;
+		printk(KERN_ERR "Request key size is [%Zd]; minimum key size "
+		       "supported by cipher [%s] is [%d]\n", key_size,
+		       cipher_name, crypto_tfm_alg_min_keysize(*tfm));
+		goto out;
+	}
+	if (key_size < crypto_tfm_alg_min_keysize(*key_tfm)) {
+		rc = -EINVAL;
+		printk(KERN_ERR "Request key size is [%Zd]; minimum key size "
+		       "supported by cipher [%s] is [%d]\n", key_size,
+		       cipher_name, crypto_tfm_alg_min_keysize(*key_tfm));
+		goto out;
+	}
+	if (key_size > crypto_tfm_alg_max_keysize(*tfm)) {
+		rc = -EINVAL;
+		printk(KERN_ERR "Request key size is [%Zd]; maximum key size "
+		       "supported by cipher [%s] is [%d]\n", key_size,
+		       cipher_name, crypto_tfm_alg_min_keysize(*tfm));
+		goto out;
+	}
+	if (key_size > crypto_tfm_alg_max_keysize(*key_tfm)) {
+		rc = -EINVAL;
+		printk(KERN_ERR "Request key size is [%Zd]; maximum key size "
+		       "supported by cipher [%s] is [%d]\n", key_size,
+		       cipher_name, crypto_tfm_alg_min_keysize(*key_tfm));
+		goto out;
+	}
+	get_random_bytes(dummy_key, key_size);
+	rc = crypto_cipher_setkey(*tfm, dummy_key, key_size);
+	if (rc) {
+		printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
+		       "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc);
+		rc = -EINVAL;
+		goto out;
+	}
+	rc = crypto_cipher_setkey(*key_tfm, dummy_key, key_size);
+	if (rc) {
+		printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
+		       "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc);
+		rc = -EINVAL;
+		goto out;
+	}
+out:
+	return rc;
+}
diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c
new file mode 100644
index 0000000..61f8e89
--- /dev/null
+++ b/fs/ecryptfs/debug.c
@@ -0,0 +1,123 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * Functions only useful for debugging.
+ *
+ * Copyright (C) 2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.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 "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_dump_auth_tok - debug function to print auth toks
+ *
+ * This function will print the contents of an ecryptfs authentication
+ * token.
+ */
+void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok)
+{
+	char salt[ECRYPTFS_SALT_SIZE * 2 + 1];
+	char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+
+	ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n",
+			auth_tok);
+	if (ECRYPTFS_CHECK_FLAG(auth_tok->flags, ECRYPTFS_PRIVATE_KEY)) {
+		ecryptfs_printk(KERN_DEBUG, " * private key type\n");
+		ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT "
+				"IN ECRYPTFS VERSION 0.1)\n");
+	} else {
+		ecryptfs_printk(KERN_DEBUG, " * passphrase type\n");
+		ecryptfs_to_hex(salt, auth_tok->token.password.salt,
+				ECRYPTFS_SALT_SIZE);
+		salt[ECRYPTFS_SALT_SIZE * 2] = '\0';
+		ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt);
+		if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
+					ECRYPTFS_PERSISTENT_PASSWORD)) {
+			ecryptfs_printk(KERN_DEBUG, " * persistent\n");
+		}
+		memcpy(sig, auth_tok->token.password.signature,
+		       ECRYPTFS_SIG_SIZE_HEX);
+		sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+		ecryptfs_printk(KERN_DEBUG, " * signature = [%s]\n", sig);
+	}
+	ecryptfs_printk(KERN_DEBUG, " * session_key.flags = [0x%x]\n",
+			auth_tok->session_key.flags);
+	if (auth_tok->session_key.flags
+	    & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT)
+		ecryptfs_printk(KERN_DEBUG,
+				" * Userspace decrypt request set\n");
+	if (auth_tok->session_key.flags
+	    & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT)
+		ecryptfs_printk(KERN_DEBUG,
+				" * Userspace encrypt request set\n");
+	if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) {
+		ecryptfs_printk(KERN_DEBUG, " * Contains decrypted key\n");
+		ecryptfs_printk(KERN_DEBUG,
+				" * session_key.decrypted_key_size = [0x%x]\n",
+				auth_tok->session_key.decrypted_key_size);
+		ecryptfs_printk(KERN_DEBUG, " * Decrypted session key "
+				"dump:\n");
+		if (ecryptfs_verbosity > 0)
+			ecryptfs_dump_hex(auth_tok->session_key.decrypted_key,
+					  ECRYPTFS_DEFAULT_KEY_BYTES);
+	}
+	if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) {
+		ecryptfs_printk(KERN_DEBUG, " * Contains encrypted key\n");
+		ecryptfs_printk(KERN_DEBUG,
+				" * session_key.encrypted_key_size = [0x%x]\n",
+				auth_tok->session_key.encrypted_key_size);
+		ecryptfs_printk(KERN_DEBUG, " * Encrypted session key "
+				"dump:\n");
+		if (ecryptfs_verbosity > 0)
+			ecryptfs_dump_hex(auth_tok->session_key.encrypted_key,
+					  auth_tok->session_key.
+					  encrypted_key_size);
+	}
+}
+
+/**
+ * ecryptfs_dump_hex - debug hex printer
+ * @data: string of bytes to be printed
+ * @bytes: number of bytes to print
+ *
+ * Dump hexadecimal representation of char array
+ */
+void ecryptfs_dump_hex(char *data, int bytes)
+{
+	int i = 0;
+	int add_newline = 1;
+
+	if (ecryptfs_verbosity < 1)
+		return;
+	if (bytes != 0) {
+		printk(KERN_DEBUG "0x%.2x.", (unsigned char)data[i]);
+		i++;
+	}
+	while (i < bytes) {
+		printk("0x%.2x.", (unsigned char)data[i]);
+		i++;
+		if (i % 16 == 0) {
+			printk("\n");
+			add_newline = 0;
+		} else
+			add_newline = 1;
+	}
+	if (add_newline)
+		printk("\n");
+}
+
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
new file mode 100644
index 0000000..f0d2a43
--- /dev/null
+++ b/fs/ecryptfs/dentry.c
@@ -0,0 +1,87 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.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 <linux/dcache.h>
+#include <linux/namei.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_d_revalidate - revalidate an ecryptfs dentry
+ * @dentry: The ecryptfs dentry
+ * @nd: The associated nameidata
+ *
+ * Called when the VFS needs to revalidate a dentry. This
+ * is called whenever a name lookup finds a dentry in the
+ * dcache. Most filesystems leave this as NULL, because all their
+ * dentries in the dcache are valid.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ *
+ */
+static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+	struct dentry *dentry_save;
+	struct vfsmount *vfsmount_save;
+	int rc = 1;
+
+	if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
+		goto out;
+	dentry_save = nd->dentry;
+	vfsmount_save = nd->mnt;
+	nd->dentry = lower_dentry;
+	nd->mnt = lower_mnt;
+	rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
+	nd->dentry = dentry_save;
+	nd->mnt = vfsmount_save;
+out:
+	return rc;
+}
+
+struct kmem_cache *ecryptfs_dentry_info_cache;
+
+/**
+ * ecryptfs_d_release
+ * @dentry: The ecryptfs dentry
+ *
+ * Called when a dentry is really deallocated.
+ */
+static void ecryptfs_d_release(struct dentry *dentry)
+{
+	struct dentry *lower_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	if (ecryptfs_dentry_to_private(dentry))
+		kmem_cache_free(ecryptfs_dentry_info_cache,
+				ecryptfs_dentry_to_private(dentry));
+	if (lower_dentry)
+		dput(lower_dentry);
+	return;
+}
+
+struct dentry_operations ecryptfs_dops = {
+	.d_revalidate = ecryptfs_d_revalidate,
+	.d_release = ecryptfs_d_release,
+};
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
new file mode 100644
index 0000000..872c995
--- /dev/null
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -0,0 +1,482 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * Kernel declarations.
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.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 ECRYPTFS_KERNEL_H
+#define ECRYPTFS_KERNEL_H
+
+#include <keys/user-type.h>
+#include <linux/fs.h>
+#include <linux/scatterlist.h>
+
+/* Version verification for shared data structures w/ userspace */
+#define ECRYPTFS_VERSION_MAJOR 0x00
+#define ECRYPTFS_VERSION_MINOR 0x04
+#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x01
+/* These flags indicate which features are supported by the kernel
+ * module; userspace tools such as the mount helper read
+ * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
+ * how to behave. */
+#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001
+#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002
+#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
+#define ECRYPTFS_VERSIONING_POLICY 0x00000008
+#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
+                                  | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH)
+
+#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
+#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
+#define ECRYPTFS_SALT_SIZE 8
+#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
+/* The original signature size is only for what is stored on disk; all
+ * in-memory representations are expanded hex, so it better adapted to
+ * be passed around or referenced on the command line */
+#define ECRYPTFS_SIG_SIZE 8
+#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
+#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
+#define ECRYPTFS_MAX_KEY_BYTES 64
+#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
+#define ECRYPTFS_DEFAULT_IV_BYTES 16
+#define ECRYPTFS_FILE_VERSION 0x01
+#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192
+#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
+#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192
+
+#define RFC2440_CIPHER_DES3_EDE 0x02
+#define RFC2440_CIPHER_CAST_5 0x03
+#define RFC2440_CIPHER_BLOWFISH 0x04
+#define RFC2440_CIPHER_AES_128 0x07
+#define RFC2440_CIPHER_AES_192 0x08
+#define RFC2440_CIPHER_AES_256 0x09
+#define RFC2440_CIPHER_TWOFISH 0x0a
+#define RFC2440_CIPHER_CAST_6 0x0b
+
+#define ECRYPTFS_SET_FLAG(flag_bit_vector, flag) (flag_bit_vector |= (flag))
+#define ECRYPTFS_CLEAR_FLAG(flag_bit_vector, flag) (flag_bit_vector &= ~(flag))
+#define ECRYPTFS_CHECK_FLAG(flag_bit_vector, flag) (flag_bit_vector & (flag))
+
+/**
+ * For convenience, we may need to pass around the encrypted session
+ * key between kernel and userspace because the authentication token
+ * may not be extractable.  For example, the TPM may not release the
+ * private key, instead requiring the encrypted data and returning the
+ * decrypted data.
+ */
+struct ecryptfs_session_key {
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
+#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
+#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
+	u32 flags;
+	u32 encrypted_key_size;
+	u32 decrypted_key_size;
+	u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+	u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
+};
+
+struct ecryptfs_password {
+	u32 password_bytes;
+	s32 hash_algo;
+	u32 hash_iterations;
+	u32 session_key_encryption_key_bytes;
+#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
+#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
+	u32 flags;
+	/* Iterated-hash concatenation of salt and passphrase */
+	u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+	u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+	/* Always in expanded hex */
+	u8 salt[ECRYPTFS_SALT_SIZE];
+};
+
+enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
+
+/* May be a password or a private key */
+struct ecryptfs_auth_tok {
+	u16 version; /* 8-bit major and 8-bit minor */
+	u16 token_type;
+	u32 flags;
+	struct ecryptfs_session_key session_key;
+	u8 reserved[32];
+	union {
+		struct ecryptfs_password password;
+		/* Private key is in future eCryptfs releases */
+	} token;
+} __attribute__ ((packed));
+
+void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
+extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);
+extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
+
+struct ecryptfs_key_record {
+	unsigned char type;
+	size_t enc_key_size;
+	unsigned char sig[ECRYPTFS_SIG_SIZE];
+	unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+};
+
+struct ecryptfs_auth_tok_list {
+	struct ecryptfs_auth_tok *auth_tok;
+	struct list_head list;
+};
+
+struct ecryptfs_crypt_stat;
+struct ecryptfs_mount_crypt_stat;
+
+struct ecryptfs_page_crypt_context {
+	struct page *page;
+#define ECRYPTFS_PREPARE_COMMIT_MODE 0
+#define ECRYPTFS_WRITEPAGE_MODE      1
+	unsigned int mode;
+	union {
+		struct file *lower_file;
+		struct writeback_control *wbc;
+	} param;
+};
+
+static inline struct ecryptfs_auth_tok *
+ecryptfs_get_key_payload_data(struct key *key)
+{
+	return (struct ecryptfs_auth_tok *)
+		(((struct user_key_payload*)key->payload.data)->data);
+}
+
+#define ECRYPTFS_SUPER_MAGIC 0xf15f
+#define ECRYPTFS_MAX_KEYSET_SIZE 1024
+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
+#define ECRYPTFS_MAX_NUM_ENC_KEYS 64
+#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */
+#define ECRYPTFS_MAX_IV_BYTES 16	/* 128 bits */
+#define ECRYPTFS_SALT_BYTES 2
+#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
+#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8	/* 4*2 */
+#define ECRYPTFS_FILE_SIZE_BYTES 8
+#define ECRYPTFS_DEFAULT_CIPHER "aes"
+#define ECRYPTFS_DEFAULT_KEY_BYTES 16
+#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC
+#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
+#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
+#define MD5_DIGEST_SIZE 16
+
+/**
+ * This is the primary struct associated with each encrypted file.
+ *
+ * TODO: cache align/pack?
+ */
+struct ecryptfs_crypt_stat {
+#define ECRYPTFS_STRUCT_INITIALIZED 0x00000001
+#define ECRYPTFS_POLICY_APPLIED     0x00000002
+#define ECRYPTFS_NEW_FILE           0x00000004
+#define ECRYPTFS_ENCRYPTED          0x00000008
+#define ECRYPTFS_SECURITY_WARNING   0x00000010
+#define ECRYPTFS_ENABLE_HMAC        0x00000020
+#define ECRYPTFS_ENCRYPT_IV_PAGES   0x00000040
+#define ECRYPTFS_KEY_VALID          0x00000080
+	u32 flags;
+	unsigned int file_version;
+	size_t iv_bytes;
+	size_t num_keysigs;
+	size_t header_extent_size;
+	size_t num_header_extents_at_front;
+	size_t extent_size; /* Data extent size; default is 4096 */
+	size_t key_size;
+	size_t extent_shift;
+	unsigned int extent_mask;
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+	struct crypto_tfm *tfm;
+	struct crypto_tfm *md5_tfm; /* Crypto context for generating
+				     * the initialization vectors */
+	unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+	unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
+	unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
+	unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX];
+	struct mutex cs_tfm_mutex;
+	struct mutex cs_md5_tfm_mutex;
+	struct mutex cs_mutex;
+};
+
+/* inode private data. */
+struct ecryptfs_inode_info {
+	struct inode vfs_inode;
+	struct inode *wii_inode;
+	struct ecryptfs_crypt_stat crypt_stat;
+};
+
+/* dentry private data. Each dentry must keep track of a lower
+ * vfsmount too. */
+struct ecryptfs_dentry_info {
+	struct dentry *wdi_dentry;
+	struct vfsmount *lower_mnt;
+	struct ecryptfs_crypt_stat *crypt_stat;
+};
+
+/**
+ * This struct is to enable a mount-wide passphrase/salt combo. This
+ * is more or less a stopgap to provide similar functionality to other
+ * crypto filesystems like EncFS or CFS until full policy support is
+ * implemented in eCryptfs.
+ */
+struct ecryptfs_mount_crypt_stat {
+	/* Pointers to memory we do not own, do not free these */
+#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001
+	u32 flags;
+	struct ecryptfs_auth_tok *global_auth_tok;
+	struct key *global_auth_tok_key;
+	size_t global_default_cipher_key_size;
+	struct crypto_tfm *global_key_tfm;
+	struct mutex global_key_tfm_mutex;
+	unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
+						 + 1];
+	unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+};
+
+/* superblock private data. */
+struct ecryptfs_sb_info {
+	struct super_block *wsi_sb;
+	struct ecryptfs_mount_crypt_stat mount_crypt_stat;
+};
+
+/* file private data. */
+struct ecryptfs_file_info {
+	struct file *wfi_file;
+	struct ecryptfs_crypt_stat *crypt_stat;
+};
+
+/* auth_tok <=> encrypted_session_key mappings */
+struct ecryptfs_auth_tok_list_item {
+	unsigned char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES];
+	struct list_head list;
+	struct ecryptfs_auth_tok auth_tok;
+};
+
+static inline struct ecryptfs_file_info *
+ecryptfs_file_to_private(struct file *file)
+{
+	return (struct ecryptfs_file_info *)file->private_data;
+}
+
+static inline void
+ecryptfs_set_file_private(struct file *file,
+			  struct ecryptfs_file_info *file_info)
+{
+	file->private_data = file_info;
+}
+
+static inline struct file *ecryptfs_file_to_lower(struct file *file)
+{
+	return ((struct ecryptfs_file_info *)file->private_data)->wfi_file;
+}
+
+static inline void
+ecryptfs_set_file_lower(struct file *file, struct file *lower_file)
+{
+	((struct ecryptfs_file_info *)file->private_data)->wfi_file =
+		lower_file;
+}
+
+static inline struct ecryptfs_inode_info *
+ecryptfs_inode_to_private(struct inode *inode)
+{
+	return container_of(inode, struct ecryptfs_inode_info, vfs_inode);
+}
+
+static inline struct inode *ecryptfs_inode_to_lower(struct inode *inode)
+{
+	return ecryptfs_inode_to_private(inode)->wii_inode;
+}
+
+static inline void
+ecryptfs_set_inode_lower(struct inode *inode, struct inode *lower_inode)
+{
+	ecryptfs_inode_to_private(inode)->wii_inode = lower_inode;
+}
+
+static inline struct ecryptfs_sb_info *
+ecryptfs_superblock_to_private(struct super_block *sb)
+{
+	return (struct ecryptfs_sb_info *)sb->s_fs_info;
+}
+
+static inline void
+ecryptfs_set_superblock_private(struct super_block *sb,
+				struct ecryptfs_sb_info *sb_info)
+{
+	sb->s_fs_info = sb_info;
+}
+
+static inline struct super_block *
+ecryptfs_superblock_to_lower(struct super_block *sb)
+{
+	return ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb;
+}
+
+static inline void
+ecryptfs_set_superblock_lower(struct super_block *sb,
+			      struct super_block *lower_sb)
+{
+	((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb = lower_sb;
+}
+
+static inline struct ecryptfs_dentry_info *
+ecryptfs_dentry_to_private(struct dentry *dentry)
+{
+	return (struct ecryptfs_dentry_info *)dentry->d_fsdata;
+}
+
+static inline void
+ecryptfs_set_dentry_private(struct dentry *dentry,
+			    struct ecryptfs_dentry_info *dentry_info)
+{
+	dentry->d_fsdata = dentry_info;
+}
+
+static inline struct dentry *
+ecryptfs_dentry_to_lower(struct dentry *dentry)
+{
+	return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry;
+}
+
+static inline void
+ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)
+{
+	((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry =
+		lower_dentry;
+}
+
+static inline struct vfsmount *
+ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)
+{
+	return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt;
+}
+
+static inline void
+ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
+{
+	((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt =
+		lower_mnt;
+}
+
+#define ecryptfs_printk(type, fmt, arg...) \
+        __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
+void __ecryptfs_printk(const char *fmt, ...);
+
+extern const struct file_operations ecryptfs_main_fops;
+extern const struct file_operations ecryptfs_dir_fops;
+extern struct inode_operations ecryptfs_main_iops;
+extern struct inode_operations ecryptfs_dir_iops;
+extern struct inode_operations ecryptfs_symlink_iops;
+extern struct super_operations ecryptfs_sops;
+extern struct dentry_operations ecryptfs_dops;
+extern struct address_space_operations ecryptfs_aops;
+extern int ecryptfs_verbosity;
+
+extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
+extern struct kmem_cache *ecryptfs_file_info_cache;
+extern struct kmem_cache *ecryptfs_dentry_info_cache;
+extern struct kmem_cache *ecryptfs_inode_info_cache;
+extern struct kmem_cache *ecryptfs_sb_info_cache;
+extern struct kmem_cache *ecryptfs_header_cache_0;
+extern struct kmem_cache *ecryptfs_header_cache_1;
+extern struct kmem_cache *ecryptfs_header_cache_2;
+extern struct kmem_cache *ecryptfs_lower_page_cache;
+
+int ecryptfs_interpose(struct dentry *hidden_dentry,
+		       struct dentry *this_dentry, struct super_block *sb,
+		       int flag);
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
+int ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+			     const char *name, int length,
+			     char **decrypted_name);
+int ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+			     const char *name, int length,
+			     char **encoded_name);
+struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src);
+void ecryptfs_dump_hex(char *data, int bytes);
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+			int sg_size);
+int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_rotate_iv(unsigned char *iv);
+void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_destruct_mount_crypt_stat(
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_write_inode_size_to_header(struct file *lower_file,
+					struct inode *lower_inode,
+					struct inode *inode);
+int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
+			    struct file *lower_file,
+			    unsigned long lower_page_index, int byte_offset,
+			    int region_bytes);
+int
+ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
+			   struct file *lower_file, int byte_offset,
+			   int region_size);
+int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
+				struct file *lower_file);
+int ecryptfs_do_readpage(struct file *file, struct page *page,
+			 pgoff_t lower_page_index);
+int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
+				     char **lower_virt,
+				     struct inode *lower_inode,
+				     unsigned long lower_page_index);
+int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
+					      struct inode *lower_inode,
+					      struct writeback_control *wbc);
+int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx);
+int ecryptfs_decrypt_page(struct file *file, struct page *page);
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+			   struct file *lower_file);
+int ecryptfs_write_headers_virt(char *page_virt,
+				struct ecryptfs_crypt_stat *crypt_stat,
+				struct dentry *ecryptfs_dentry);
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+			  struct file *lower_file);
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
+int contains_ecryptfs_marker(char *data);
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+				struct vfsmount *mnt);
+u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_generate_key_packet_set(char *dest_base,
+				     struct ecryptfs_crypt_stat *crypt_stat,
+				     struct dentry *ecryptfs_dentry,
+				     size_t *len, size_t max);
+int process_request_key_err(long err_code);
+int
+ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
+			  unsigned char *src, struct dentry *ecryptfs_dentry);
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
+int
+ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm,
+			char *cipher_name, size_t key_size);
+int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
+int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
+void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
+
+#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
new file mode 100644
index 0000000..c8550c9
--- /dev/null
+++ b/fs/ecryptfs/file.c
@@ -0,0 +1,440 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ *   		Michael C. Thompson <mcthomps@us.ibm.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 <linux/file.h>
+#include <linux/poll.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/security.h>
+#include <linux/smp_lock.h>
+#include <linux/compat.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_llseek
+ * @file: File we are seeking in
+ * @offset: The offset to seek to
+ * @origin: 2 - offset from i_size; 1 - offset from f_pos
+ *
+ * Returns the position we have seeked to, or negative on error
+ */
+static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
+{
+	loff_t rv;
+	loff_t new_end_pos;
+	int rc;
+	int expanding_file = 0;
+	struct inode *inode = file->f_mapping->host;
+
+	/* If our offset is past the end of our file, we're going to
+	 * need to grow it so we have a valid length of 0's */
+	new_end_pos = offset;
+	switch (origin) {
+	case 2:
+		new_end_pos += i_size_read(inode);
+		expanding_file = 1;
+		break;
+	case 1:
+		new_end_pos += file->f_pos;
+		if (new_end_pos > i_size_read(inode)) {
+			ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
+					"> i_size_read(inode)(=[0x%.16x])\n",
+					new_end_pos, i_size_read(inode));
+			expanding_file = 1;
+		}
+		break;
+	default:
+		if (new_end_pos > i_size_read(inode)) {
+			ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
+					"> i_size_read(inode)(=[0x%.16x])\n",
+					new_end_pos, i_size_read(inode));
+			expanding_file = 1;
+		}
+	}
+	ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
+	if (expanding_file) {
+		rc = ecryptfs_truncate(file->f_dentry, new_end_pos);
+		if (rc) {
+			rv = rc;
+			ecryptfs_printk(KERN_ERR, "Error on attempt to "
+					"truncate to (higher) offset [0x%.16x];"
+					" rc = [%d]\n", new_end_pos, rc);
+			goto out;
+		}
+	}
+	rv = generic_file_llseek(file, offset, origin);
+out:
+	return rv;
+}
+
+/**
+ * ecryptfs_read_update_atime
+ *
+ * generic_file_read updates the atime of upper layer inode.  But, it
+ * doesn't give us a chance to update the atime of the lower layer
+ * inode.  This function is a wrapper to generic_file_read.  It
+ * updates the atime of the lower level inode if generic_file_read
+ * returns without any errors. This is to be used only for file reads.
+ * The function to be used for directory reads is ecryptfs_read.
+ */
+static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
+				const struct iovec *iov,
+				unsigned long nr_segs, loff_t pos)
+{
+	int rc;
+	struct dentry *lower_dentry;
+	struct vfsmount *lower_vfsmount;
+	struct file *file = iocb->ki_filp;
+
+	rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
+	/*
+	 * Even though this is a async interface, we need to wait
+	 * for IO to finish to update atime
+	 */
+	if (-EIOCBQUEUED == rc)
+		rc = wait_on_sync_kiocb(iocb);
+	if (rc >= 0) {
+		lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry);
+		lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry);
+		touch_atime(lower_vfsmount, lower_dentry);
+	}
+	return rc;
+}
+
+struct ecryptfs_getdents_callback {
+	void *dirent;
+	struct dentry *dentry;
+	filldir_t filldir;
+	int err;
+	int filldir_called;
+	int entries_written;
+};
+
+/* Inspired by generic filldir in fs/readir.c */
+static int
+ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
+		 u64 ino, unsigned int d_type)
+{
+	struct ecryptfs_crypt_stat *crypt_stat;
+	struct ecryptfs_getdents_callback *buf =
+	    (struct ecryptfs_getdents_callback *)dirent;
+	int rc;
+	int decoded_length;
+	char *decoded_name;
+
+	crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat;
+	buf->filldir_called++;
+	decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen,
+						  &decoded_name);
+	if (decoded_length < 0) {
+		rc = decoded_length;
+		goto out;
+	}
+	rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset,
+			  ino, d_type);
+	kfree(decoded_name);
+	if (rc >= 0)
+		buf->entries_written++;
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_readdir
+ * @file: The ecryptfs file struct
+ * @dirent: Directory entry
+ * @filldir: The filldir callback function
+ */
+static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+	int rc;
+	struct file *lower_file;
+	struct inode *inode;
+	struct ecryptfs_getdents_callback buf;
+
+	lower_file = ecryptfs_file_to_lower(file);
+	lower_file->f_pos = file->f_pos;
+	inode = file->f_dentry->d_inode;
+	memset(&buf, 0, sizeof(buf));
+	buf.dirent = dirent;
+	buf.dentry = file->f_dentry;
+	buf.filldir = filldir;
+retry:
+	buf.filldir_called = 0;
+	buf.entries_written = 0;
+	buf.err = 0;
+	rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
+	if (buf.err)
+		rc = buf.err;
+	if (buf.filldir_called && !buf.entries_written)
+		goto retry;
+	file->f_pos = lower_file->f_pos;
+	if (rc >= 0)
+		ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
+	return rc;
+}
+
+struct kmem_cache *ecryptfs_file_info_cache;
+
+/**
+ * ecryptfs_open
+ * @inode: inode speciying file to open
+ * @file: Structure to return filled in
+ *
+ * Opens the file specified by inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_open(struct inode *inode, struct file *file)
+{
+	int rc = 0;
+	struct ecryptfs_crypt_stat *crypt_stat = NULL;
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+	struct dentry *ecryptfs_dentry = file->f_dentry;
+	/* Private value of ecryptfs_dentry allocated in
+	 * ecryptfs_lookup() */
+	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+	struct inode *lower_inode = NULL;
+	struct file *lower_file = NULL;
+	struct vfsmount *lower_mnt;
+	struct ecryptfs_file_info *file_info;
+	int lower_flags;
+
+	/* Released in ecryptfs_release or end of function if failure */
+	file_info = kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL);
+	ecryptfs_set_file_private(file, file_info);
+	if (!file_info) {
+		ecryptfs_printk(KERN_ERR,
+				"Error attempting to allocate memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(file_info, 0, sizeof(*file_info));
+	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+	mount_crypt_stat = &ecryptfs_superblock_to_private(
+		ecryptfs_dentry->d_sb)->mount_crypt_stat;
+	mutex_lock(&crypt_stat->cs_mutex);
+	if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) {
+		ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
+		/* Policy code enabled in future release */
+		ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED);
+		ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+	}
+	mutex_unlock(&crypt_stat->cs_mutex);
+	/* This mntget & dget is undone via fput when the file is released */
+	dget(lower_dentry);
+	lower_flags = file->f_flags;
+	if ((lower_flags & O_ACCMODE) == O_WRONLY)
+		lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
+	if (file->f_flags & O_APPEND)
+		lower_flags &= ~O_APPEND;
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+	mntget(lower_mnt);
+	/* Corresponding fput() in ecryptfs_release() */
+	lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags);
+	if (IS_ERR(lower_file)) {
+		rc = PTR_ERR(lower_file);
+		ecryptfs_printk(KERN_ERR, "Error opening lower file\n");
+		goto out_puts;
+	}
+	ecryptfs_set_file_lower(file, lower_file);
+	/* Isn't this check the same as the one in lookup? */
+	lower_inode = lower_dentry->d_inode;
+	if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+		ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+		ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+		rc = 0;
+		goto out;
+	}
+	mutex_lock(&crypt_stat->cs_mutex);
+	if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+		if (!(mount_crypt_stat->flags
+		      & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+			rc = -EIO;
+			printk(KERN_WARNING "Attempt to read file that is "
+			       "not in a valid eCryptfs format, and plaintext "
+			       "passthrough mode is not enabled; returning "
+			       "-EIO\n");
+			mutex_unlock(&crypt_stat->cs_mutex);
+			goto out_puts;
+		}
+		crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+		rc = 0;
+		mutex_unlock(&crypt_stat->cs_mutex);
+		goto out;
+	} else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+					ECRYPTFS_POLICY_APPLIED)
+		   || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+					   ECRYPTFS_KEY_VALID)) {
+		rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file);
+		if (rc) {
+			ecryptfs_printk(KERN_DEBUG,
+					"Valid headers not found\n");
+			if (!(mount_crypt_stat->flags
+			      & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+				rc = -EIO;
+				printk(KERN_WARNING "Attempt to read file that "
+				       "is not in a valid eCryptfs format, "
+				       "and plaintext passthrough mode is not "
+				       "enabled; returning -EIO\n");
+				mutex_unlock(&crypt_stat->cs_mutex);
+				goto out_puts;
+			}
+			ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
+					    ECRYPTFS_ENCRYPTED);
+			rc = 0;
+			mutex_unlock(&crypt_stat->cs_mutex);
+			goto out;
+		}
+	}
+	mutex_unlock(&crypt_stat->cs_mutex);
+	ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
+			"size: [0x%.16x]\n", inode, inode->i_ino,
+			i_size_read(inode));
+	ecryptfs_set_file_lower(file, lower_file);
+	goto out;
+out_puts:
+	mntput(lower_mnt);
+	dput(lower_dentry);
+	kmem_cache_free(ecryptfs_file_info_cache,
+			ecryptfs_file_to_private(file));
+out:
+	return rc;
+}
+
+static int ecryptfs_flush(struct file *file, fl_owner_t td)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+
+	lower_file = ecryptfs_file_to_lower(file);
+	if (lower_file->f_op && lower_file->f_op->flush)
+		rc = lower_file->f_op->flush(lower_file, td);
+	return rc;
+}
+
+static int ecryptfs_release(struct inode *inode, struct file *file)
+{
+	struct file *lower_file = ecryptfs_file_to_lower(file);
+	struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file);
+	struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
+
+	fput(lower_file);
+	inode->i_blocks = lower_inode->i_blocks;
+	kmem_cache_free(ecryptfs_file_info_cache, file_info);
+	return 0;
+}
+
+static int
+ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct file *lower_file = ecryptfs_file_to_lower(file);
+	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	struct inode *lower_inode = lower_dentry->d_inode;
+	int rc = -EINVAL;
+
+	if (lower_inode->i_fop->fsync) {
+		mutex_lock(&lower_inode->i_mutex);
+		rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
+					       datasync);
+		mutex_unlock(&lower_inode->i_mutex);
+	}
+	return rc;
+}
+
+static int ecryptfs_fasync(int fd, struct file *file, int flag)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+
+	lower_file = ecryptfs_file_to_lower(file);
+	if (lower_file->f_op && lower_file->f_op->fasync)
+		rc = lower_file->f_op->fasync(fd, lower_file, flag);
+	return rc;
+}
+
+static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos,
+				 size_t count, read_actor_t actor, void *target)
+{
+	struct file *lower_file = NULL;
+	int rc = -EINVAL;
+
+	lower_file = ecryptfs_file_to_lower(file);
+	if (lower_file->f_op && lower_file->f_op->sendfile)
+		rc = lower_file->f_op->sendfile(lower_file, ppos, count,
+						actor, target);
+
+	return rc;
+}
+
+static int ecryptfs_ioctl(struct inode *inode, struct file *file,
+			  unsigned int cmd, unsigned long arg);
+
+const struct file_operations ecryptfs_dir_fops = {
+	.readdir = ecryptfs_readdir,
+	.ioctl = ecryptfs_ioctl,
+	.mmap = generic_file_mmap,
+	.open = ecryptfs_open,
+	.flush = ecryptfs_flush,
+	.release = ecryptfs_release,
+	.fsync = ecryptfs_fsync,
+	.fasync = ecryptfs_fasync,
+	.sendfile = ecryptfs_sendfile,
+};
+
+const struct file_operations ecryptfs_main_fops = {
+	.llseek = ecryptfs_llseek,
+	.read = do_sync_read,
+	.aio_read = ecryptfs_read_update_atime,
+	.write = do_sync_write,
+	.aio_write = generic_file_aio_write,
+	.readdir = ecryptfs_readdir,
+	.ioctl = ecryptfs_ioctl,
+	.mmap = generic_file_mmap,
+	.open = ecryptfs_open,
+	.flush = ecryptfs_flush,
+	.release = ecryptfs_release,
+	.fsync = ecryptfs_fsync,
+	.fasync = ecryptfs_fasync,
+	.sendfile = ecryptfs_sendfile,
+};
+
+static int
+ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+	       unsigned long arg)
+{
+	int rc = 0;
+	struct file *lower_file = NULL;
+
+	if (ecryptfs_file_to_private(file))
+		lower_file = ecryptfs_file_to_lower(file);
+	if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
+		rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode),
+					     lower_file, cmd, arg);
+	else
+		rc = -ENOTTY;
+	return rc;
+}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
new file mode 100644
index 0000000..efdd2b7
--- /dev/null
+++ b/fs/ecryptfs/inode.c
@@ -0,0 +1,1079 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *              Michael C. Thompsion <mcthomps@us.ibm.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 <linux/file.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/crypto.h>
+#include "ecryptfs_kernel.h"
+
+static struct dentry *lock_parent(struct dentry *dentry)
+{
+	struct dentry *dir;
+
+	dir = dget(dentry->d_parent);
+	mutex_lock(&(dir->d_inode->i_mutex));
+	return dir;
+}
+
+static void unlock_parent(struct dentry *dentry)
+{
+	mutex_unlock(&(dentry->d_parent->d_inode->i_mutex));
+	dput(dentry->d_parent);
+}
+
+static void unlock_dir(struct dentry *dir)
+{
+	mutex_unlock(&dir->d_inode->i_mutex);
+	dput(dir);
+}
+
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src)
+{
+	i_size_write(dst, i_size_read((struct inode *)src));
+	dst->i_blocks = src->i_blocks;
+}
+
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src)
+{
+	dest->i_atime = src->i_atime;
+}
+
+static void ecryptfs_copy_attr_times(struct inode *dest,
+				     const struct inode *src)
+{
+	dest->i_atime = src->i_atime;
+	dest->i_mtime = src->i_mtime;
+	dest->i_ctime = src->i_ctime;
+}
+
+static void ecryptfs_copy_attr_timesizes(struct inode *dest,
+					 const struct inode *src)
+{
+	dest->i_atime = src->i_atime;
+	dest->i_mtime = src->i_mtime;
+	dest->i_ctime = src->i_ctime;
+	ecryptfs_copy_inode_size(dest, src);
+}
+
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src)
+{
+	dest->i_mode = src->i_mode;
+	dest->i_nlink = src->i_nlink;
+	dest->i_uid = src->i_uid;
+	dest->i_gid = src->i_gid;
+	dest->i_rdev = src->i_rdev;
+	dest->i_atime = src->i_atime;
+	dest->i_mtime = src->i_mtime;
+	dest->i_ctime = src->i_ctime;
+	dest->i_blkbits = src->i_blkbits;
+	dest->i_flags = src->i_flags;
+}
+
+/**
+ * ecryptfs_create_underlying_file
+ * @lower_dir_inode: inode of the parent in the lower fs of the new file
+ * @lower_dentry: New file's dentry in the lower fs
+ * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @mode: The mode of the new file
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
+ *
+ * Creates the file in the lower file system.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
+				struct dentry *dentry, int mode,
+				struct nameidata *nd)
+{
+	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+	struct dentry *dentry_save;
+	struct vfsmount *vfsmount_save;
+	int rc;
+
+	dentry_save = nd->dentry;
+	vfsmount_save = nd->mnt;
+	nd->dentry = lower_dentry;
+	nd->mnt = lower_mnt;
+	rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
+	nd->dentry = dentry_save;
+	nd->mnt = vfsmount_save;
+	return rc;
+}
+
+/**
+ * ecryptfs_do_create
+ * @directory_inode: inode of the new file's dentry's parent in ecryptfs
+ * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @mode: The mode of the new file
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
+ *
+ * Creates the underlying file and the eCryptfs inode which will link to
+ * it. It will also update the eCryptfs directory inode to mimic the
+ * stat of the lower directory inode.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_do_create(struct inode *directory_inode,
+		   struct dentry *ecryptfs_dentry, int mode,
+		   struct nameidata *nd)
+{
+	int rc;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	if (unlikely(IS_ERR(lower_dir_dentry))) {
+		ecryptfs_printk(KERN_ERR, "Error locking directory of "
+				"dentry\n");
+		rc = PTR_ERR(lower_dir_dentry);
+		goto out;
+	}
+	rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
+					     ecryptfs_dentry, mode, nd);
+	if (unlikely(rc)) {
+		ecryptfs_printk(KERN_ERR,
+				"Failure to create underlying file\n");
+		goto out_lock;
+	}
+	rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
+				directory_inode->i_sb, 0);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
+		goto out_lock;
+	}
+	ecryptfs_copy_attr_timesizes(directory_inode,
+				     lower_dir_dentry->d_inode);
+out_lock:
+	unlock_dir(lower_dir_dentry);
+out:
+	return rc;
+}
+
+/**
+ * grow_file
+ * @ecryptfs_dentry: the ecryptfs dentry
+ * @lower_file: The lower file
+ * @inode: The ecryptfs inode
+ * @lower_inode: The lower inode
+ *
+ * This is the code which will grow the file to its correct size.
+ */
+static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
+		     struct inode *inode, struct inode *lower_inode)
+{
+	int rc = 0;
+	struct file fake_file;
+	struct ecryptfs_file_info tmp_file_info;
+
+	memset(&fake_file, 0, sizeof(fake_file));
+	fake_file.f_dentry = ecryptfs_dentry;
+	memset(&tmp_file_info, 0, sizeof(tmp_file_info));
+	ecryptfs_set_file_private(&fake_file, &tmp_file_info);
+	ecryptfs_set_file_lower(&fake_file, lower_file);
+	rc = ecryptfs_fill_zeros(&fake_file, 1);
+	if (rc) {
+		ECRYPTFS_SET_FLAG(
+			ecryptfs_inode_to_private(inode)->crypt_stat.flags,
+			ECRYPTFS_SECURITY_WARNING);
+		ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros "
+				"in file; rc = [%d]\n", rc);
+		goto out;
+	}
+	i_size_write(inode, 0);
+	ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+	ECRYPTFS_SET_FLAG(ecryptfs_inode_to_private(inode)->crypt_stat.flags,
+			  ECRYPTFS_NEW_FILE);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_initialize_file
+ *
+ * Cause the file to be changed from a basic empty file to an ecryptfs
+ * file with a header and first data page.
+ *
+ * Returns zero on success
+ */
+static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
+{
+	int rc = 0;
+	int lower_flags;
+	struct ecryptfs_crypt_stat *crypt_stat;
+	struct dentry *lower_dentry;
+	struct dentry *tlower_dentry = NULL;
+	struct file *lower_file;
+	struct inode *inode, *lower_inode;
+	struct vfsmount *lower_mnt;
+
+	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+	ecryptfs_printk(KERN_DEBUG, "lower_dentry->d_name.name = [%s]\n",
+			lower_dentry->d_name.name);
+	inode = ecryptfs_dentry->d_inode;
+	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+	tlower_dentry = dget(lower_dentry);
+	if (!tlower_dentry) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry\n");
+		goto out;
+	}
+	lower_flags = ((O_CREAT | O_WRONLY | O_TRUNC) & O_ACCMODE) | O_RDWR;
+#if BITS_PER_LONG != 32
+	lower_flags |= O_LARGEFILE;
+#endif
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+	mntget(lower_mnt);
+	/* Corresponding fput() at end of this function */
+	lower_file = dentry_open(tlower_dentry, lower_mnt, lower_flags);
+	if (IS_ERR(lower_file)) {
+		rc = PTR_ERR(lower_file);
+		ecryptfs_printk(KERN_ERR,
+				"Error opening dentry; rc = [%i]\n", rc);
+		goto out;
+	}
+	/* fput(lower_file) should handle the puts if we do this */
+	lower_file->f_dentry = tlower_dentry;
+	lower_file->f_vfsmnt = lower_mnt;
+	lower_inode = tlower_dentry->d_inode;
+	if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+		ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+		ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+		goto out_fput;
+	}
+	ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
+	ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n");
+	rc = ecryptfs_new_file_context(ecryptfs_dentry);
+	if (rc) {
+		ecryptfs_printk(KERN_DEBUG, "Error creating new file "
+				"context\n");
+		goto out_fput;
+	}
+	rc = ecryptfs_write_headers(ecryptfs_dentry, lower_file);
+	if (rc) {
+		ecryptfs_printk(KERN_DEBUG, "Error writing headers\n");
+		goto out_fput;
+	}
+	rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode);
+out_fput:
+	fput(lower_file);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_create
+ * @dir: The inode of the directory in which to create the file.
+ * @dentry: The eCryptfs dentry
+ * @mode: The mode of the new file.
+ * @nd: nameidata
+ *
+ * Creates a new file.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
+		int mode, struct nameidata *nd)
+{
+	int rc;
+
+	rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);
+	if (unlikely(rc)) {
+		ecryptfs_printk(KERN_WARNING, "Failed to create file in"
+				"lower filesystem\n");
+		goto out;
+	}
+	/* At this point, a file exists on "disk"; we need to make sure
+	 * that this on disk file is prepared to be an ecryptfs file */
+	rc = ecryptfs_initialize_file(ecryptfs_dentry);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_lookup
+ * @dir: inode
+ * @dentry: The dentry
+ * @nd: nameidata, may be NULL
+ *
+ * Find a file on disk. If the file does not exist, then we'll add it to the
+ * dentry cache and continue on to read it from the disk.
+ */
+static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
+				      struct nameidata *nd)
+{
+	int rc = 0;
+	struct dentry *lower_dir_dentry;
+	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
+	struct dentry *tlower_dentry = NULL;
+	char *encoded_name;
+	unsigned int encoded_namelen;
+	struct ecryptfs_crypt_stat *crypt_stat = NULL;
+	char *page_virt = NULL;
+	struct inode *lower_inode;
+	u64 file_size;
+
+	lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
+	dentry->d_op = &ecryptfs_dops;
+	if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, "."))
+	    || (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, "..")))
+		goto out_drop;
+	encoded_namelen = ecryptfs_encode_filename(crypt_stat,
+						   dentry->d_name.name,
+						   dentry->d_name.len,
+						   &encoded_name);
+	if (encoded_namelen < 0) {
+		rc = encoded_namelen;
+		goto out_drop;
+	}
+	ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen "
+			"= [%d]\n", encoded_name, encoded_namelen);
+	lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry,
+				      encoded_namelen - 1);
+	kfree(encoded_name);
+	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
+	if (IS_ERR(lower_dentry)) {
+		ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n");
+		rc = PTR_ERR(lower_dentry);
+		goto out_drop;
+	}
+	ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->"
+       		"d_name.name = [%s]\n", lower_dentry,
+		lower_dentry->d_name.name);
+	lower_inode = lower_dentry->d_inode;
+	ecryptfs_copy_attr_atime(dir, lower_dir_dentry->d_inode);
+	BUG_ON(!atomic_read(&lower_dentry->d_count));
+	ecryptfs_set_dentry_private(dentry,
+				    kmem_cache_alloc(ecryptfs_dentry_info_cache,
+						     SLAB_KERNEL));
+	if (!ecryptfs_dentry_to_private(dentry)) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR, "Out of memory whilst attempting "
+				"to allocate ecryptfs_dentry_info struct\n");
+		goto out_dput;
+	}
+	ecryptfs_set_dentry_lower(dentry, lower_dentry);
+	ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt);
+	if (!lower_dentry->d_inode) {
+		/* We want to add because we couldn't find in lower */
+		d_add(dentry, NULL);
+		goto out;
+	}
+	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 1);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error interposing\n");
+		goto out_dput;
+	}
+	if (S_ISDIR(lower_inode->i_mode)) {
+		ecryptfs_printk(KERN_DEBUG, "Is a directory; returning\n");
+		goto out;
+	}
+	if (S_ISLNK(lower_inode->i_mode)) {
+		ecryptfs_printk(KERN_DEBUG, "Is a symlink; returning\n");
+		goto out;
+	}
+	if (!nd) {
+		ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave"
+				"as we *think* we are about to unlink\n");
+		goto out;
+	}
+	tlower_dentry = dget(lower_dentry);
+	if (!tlower_dentry || IS_ERR(tlower_dentry)) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR, "Cannot dget lower_dentry\n");
+		goto out_dput;
+	}
+	/* Released in this function */
+	page_virt =
+	    (char *)kmem_cache_alloc(ecryptfs_header_cache_2,
+				     SLAB_USER);
+	if (!page_virt) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR,
+				"Cannot ecryptfs_kmalloc a page\n");
+		goto out_dput;
+	}
+	memset(page_virt, 0, PAGE_CACHE_SIZE);
+	rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd->mnt);
+	crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+	if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED))
+		ecryptfs_set_default_sizes(crypt_stat);
+	if (rc) {
+		rc = 0;
+		ecryptfs_printk(KERN_WARNING, "Error reading header region;"
+				" assuming unencrypted\n");
+	} else {
+		if (!contains_ecryptfs_marker(page_virt
+					      + ECRYPTFS_FILE_SIZE_BYTES)) {
+			kmem_cache_free(ecryptfs_header_cache_2, page_virt);
+			goto out;
+		}
+		memcpy(&file_size, page_virt, sizeof(file_size));
+		file_size = be64_to_cpu(file_size);
+		i_size_write(dentry->d_inode, (loff_t)file_size);
+	}
+	kmem_cache_free(ecryptfs_header_cache_2, page_virt);
+	goto out;
+
+out_dput:
+	dput(lower_dentry);
+	if (tlower_dentry)
+		dput(tlower_dentry);
+out_drop:
+	d_drop(dentry);
+out:
+	return ERR_PTR(rc);
+}
+
+static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
+			 struct dentry *new_dentry)
+{
+	struct dentry *lower_old_dentry;
+	struct dentry *lower_new_dentry;
+	struct dentry *lower_dir_dentry;
+	u64 file_size_save;
+	int rc;
+
+	file_size_save = i_size_read(old_dentry->d_inode);
+	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+	dget(lower_old_dentry);
+	dget(lower_new_dentry);
+	lower_dir_dentry = lock_parent(lower_new_dentry);
+	rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
+		      lower_new_dentry);
+	if (rc || !lower_new_dentry->d_inode)
+		goto out_lock;
+	rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
+	if (rc)
+		goto out_lock;
+	ecryptfs_copy_attr_timesizes(dir, lower_new_dentry->d_inode);
+	old_dentry->d_inode->i_nlink =
+		ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
+	i_size_write(new_dentry->d_inode, file_size_save);
+out_lock:
+	unlock_dir(lower_dir_dentry);
+	dput(lower_new_dentry);
+	dput(lower_old_dentry);
+	if (!new_dentry->d_inode)
+		d_drop(new_dentry);
+	return rc;
+}
+
+static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+	int rc = 0;
+	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
+
+	lock_parent(lower_dentry);
+	rc = vfs_unlink(lower_dir_inode, lower_dentry);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error in vfs_unlink\n");
+		goto out_unlock;
+	}
+	ecryptfs_copy_attr_times(dir, lower_dir_inode);
+	dentry->d_inode->i_nlink =
+		ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;
+	dentry->d_inode->i_ctime = dir->i_ctime;
+out_unlock:
+	unlock_parent(lower_dentry);
+	return rc;
+}
+
+static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
+			    const char *symname)
+{
+	int rc;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+	umode_t mode;
+	char *encoded_symname;
+	unsigned int encoded_symlen;
+	struct ecryptfs_crypt_stat *crypt_stat = NULL;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	dget(lower_dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	mode = S_IALLUGO;
+	encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
+						  strlen(symname),
+						  &encoded_symname);
+	if (encoded_symlen < 0) {
+		rc = encoded_symlen;
+		goto out_lock;
+	}
+	rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
+			 encoded_symname, mode);
+	kfree(encoded_symname);
+	if (rc || !lower_dentry->d_inode)
+		goto out_lock;
+	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+	if (rc)
+		goto out_lock;
+	ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out_lock:
+	unlock_dir(lower_dir_dentry);
+	dput(lower_dentry);
+	if (!dentry->d_inode)
+		d_drop(dentry);
+	return rc;
+}
+
+static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	int rc;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
+	if (rc || !lower_dentry->d_inode)
+		goto out;
+	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+	if (rc)
+		goto out;
+	ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+out:
+	unlock_dir(lower_dir_dentry);
+	if (!dentry->d_inode)
+		d_drop(dentry);
+	return rc;
+}
+
+static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	int rc = 0;
+	struct dentry *tdentry = NULL;
+	struct dentry *lower_dentry;
+	struct dentry *tlower_dentry = NULL;
+	struct dentry *lower_dir_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	if (!(tdentry = dget(dentry))) {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_ERR, "Error dget'ing dentry [%p]\n",
+				dentry);
+		goto out;
+	}
+	lower_dir_dentry = lock_parent(lower_dentry);
+	if (!(tlower_dentry = dget(lower_dentry))) {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry "
+				"[%p]\n", lower_dentry);
+		goto out;
+	}
+	rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
+	if (!rc) {
+		d_delete(tlower_dentry);
+		tlower_dentry = NULL;
+	}
+	ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
+	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+	unlock_dir(lower_dir_dentry);
+	if (!rc)
+		d_drop(dentry);
+out:
+	if (tdentry)
+		dput(tdentry);
+	if (tlower_dentry)
+		dput(tlower_dentry);
+	return rc;
+}
+
+static int
+ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+	int rc;
+	struct dentry *lower_dentry;
+	struct dentry *lower_dir_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	lower_dir_dentry = lock_parent(lower_dentry);
+	rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
+	if (rc || !lower_dentry->d_inode)
+		goto out;
+	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+	if (rc)
+		goto out;
+	ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out:
+	unlock_dir(lower_dir_dentry);
+	if (!dentry->d_inode)
+		d_drop(dentry);
+	return rc;
+}
+
+static int
+ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+		struct inode *new_dir, struct dentry *new_dentry)
+{
+	int rc;
+	struct dentry *lower_old_dentry;
+	struct dentry *lower_new_dentry;
+	struct dentry *lower_old_dir_dentry;
+	struct dentry *lower_new_dir_dentry;
+
+	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+	dget(lower_old_dentry);
+	dget(lower_new_dentry);
+	lower_old_dir_dentry = dget_parent(lower_old_dentry);
+	lower_new_dir_dentry = dget_parent(lower_new_dentry);
+	lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+	rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
+			lower_new_dir_dentry->d_inode, lower_new_dentry);
+	if (rc)
+		goto out_lock;
+	ecryptfs_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
+	if (new_dir != old_dir)
+		ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
+out_lock:
+	unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+	dput(lower_new_dentry);
+	dput(lower_old_dentry);
+	return rc;
+}
+
+static int
+ecryptfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz)
+{
+	int rc;
+	struct dentry *lower_dentry;
+	char *decoded_name;
+	char *lower_buf;
+	mm_segment_t old_fs;
+	struct ecryptfs_crypt_stat *crypt_stat;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	if (!lower_dentry->d_inode->i_op ||
+	    !lower_dentry->d_inode->i_op->readlink) {
+		rc = -EINVAL;
+		goto out;
+	}
+	/* Released in this function */
+	lower_buf = kmalloc(bufsiz, GFP_KERNEL);
+	if (lower_buf == NULL) {
+		ecryptfs_printk(KERN_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	old_fs = get_fs();
+	set_fs(get_ds());
+	ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
+			"lower_dentry->d_name.name = [%s]\n",
+			lower_dentry->d_name.name);
+	rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
+						   (char __user *)lower_buf,
+						   bufsiz);
+	set_fs(old_fs);
+	if (rc >= 0) {
+		crypt_stat = NULL;
+		rc = ecryptfs_decode_filename(crypt_stat, lower_buf, rc,
+					      &decoded_name);
+		if (rc == -ENOMEM)
+			goto out_free_lower_buf;
+		if (rc > 0) {
+			ecryptfs_printk(KERN_DEBUG, "Copying [%d] bytes "
+					"to userspace: [%*s]\n", rc,
+					decoded_name);
+			if (copy_to_user(buf, decoded_name, rc))
+				rc = -EFAULT;
+		}
+		kfree(decoded_name);
+		ecryptfs_copy_attr_atime(dentry->d_inode,
+					 lower_dentry->d_inode);
+	}
+out_free_lower_buf:
+	kfree(lower_buf);
+out:
+	return rc;
+}
+
+static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	char *buf;
+	int len = PAGE_SIZE, rc;
+	mm_segment_t old_fs;
+
+	/* Released in ecryptfs_put_link(); only release here on error */
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	old_fs = get_fs();
+	set_fs(get_ds());
+	ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
+			"dentry->d_name.name = [%s]\n", dentry->d_name.name);
+	rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
+	buf[rc] = '\0';
+	set_fs(old_fs);
+	if (rc < 0)
+		goto out_free;
+	rc = 0;
+	nd_set_link(nd, buf);
+	goto out;
+out_free:
+	kfree(buf);
+out:
+	return ERR_PTR(rc);
+}
+
+static void
+ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+{
+	/* Free the char* */
+	kfree(nd_get_link(nd));
+}
+
+/**
+ * upper_size_to_lower_size
+ * @crypt_stat: Crypt_stat associated with file
+ * @upper_size: Size of the upper file
+ *
+ * Calculate the requried size of the lower file based on the
+ * specified size of the upper file. This calculation is based on the
+ * number of headers in the underlying file and the extent size.
+ *
+ * Returns Calculated size of the lower file.
+ */
+static loff_t
+upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
+			 loff_t upper_size)
+{
+	loff_t lower_size;
+
+	lower_size = ( crypt_stat->header_extent_size
+		       * crypt_stat->num_header_extents_at_front );
+	if (upper_size != 0) {
+		loff_t num_extents;
+
+		num_extents = upper_size >> crypt_stat->extent_shift;
+		if (upper_size & ~crypt_stat->extent_mask)
+			num_extents++;
+		lower_size += (num_extents * crypt_stat->extent_size);
+	}
+	return lower_size;
+}
+
+/**
+ * ecryptfs_truncate
+ * @dentry: The ecryptfs layer dentry
+ * @new_length: The length to expand the file to
+ *
+ * Function to handle truncations modifying the size of the file. Note
+ * that the file sizes are interpolated. When expanding, we are simply
+ * writing strings of 0's out. When truncating, we need to modify the
+ * underlying file size according to the page index interpolations.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
+{
+	int rc = 0;
+	struct inode *inode = dentry->d_inode;
+	struct dentry *lower_dentry;
+	struct vfsmount *lower_mnt;
+	struct file fake_ecryptfs_file, *lower_file = NULL;
+	struct ecryptfs_crypt_stat *crypt_stat;
+	loff_t i_size = i_size_read(inode);
+	loff_t lower_size_before_truncate;
+	loff_t lower_size_after_truncate;
+
+	if (unlikely((new_length == i_size)))
+		goto out;
+	crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+	/* Set up a fake ecryptfs file, this is used to interface with
+	 * the file in the underlying filesystem so that the
+	 * truncation has an effect there as well. */
+	memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file));
+	fake_ecryptfs_file.f_dentry = dentry;
+	/* Released at out_free: label */
+	ecryptfs_set_file_private(&fake_ecryptfs_file,
+				  kmem_cache_alloc(ecryptfs_file_info_cache,
+						   SLAB_KERNEL));
+	if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	/* This dget & mntget is released through fput at out_fput: */
+	dget(lower_dentry);
+	lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+	mntget(lower_mnt);
+	lower_file = dentry_open(lower_dentry, lower_mnt, O_RDWR);
+	if (unlikely(IS_ERR(lower_file))) {
+		rc = PTR_ERR(lower_file);
+		goto out_free;
+	}
+	ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file);
+	/* Switch on growing or shrinking file */
+	if (new_length > i_size) {
+		rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR,
+					"Problem with fill_zeros\n");
+			goto out_fput;
+		}
+		i_size_write(inode, new_length);
+		rc = ecryptfs_write_inode_size_to_header(lower_file,
+							 lower_dentry->d_inode,
+							 inode);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR,
+					"Problem with ecryptfs_write"
+					"_inode_size\n");
+			goto out_fput;
+		}
+	} else { /* new_length < i_size_read(inode) */
+		vmtruncate(inode, new_length);
+		ecryptfs_write_inode_size_to_header(lower_file,
+						    lower_dentry->d_inode,
+						    inode);
+		/* We are reducing the size of the ecryptfs file, and need to
+		 * know if we need to reduce the size of the lower file. */
+		lower_size_before_truncate =
+		    upper_size_to_lower_size(crypt_stat, i_size);
+		lower_size_after_truncate =
+		    upper_size_to_lower_size(crypt_stat, new_length);
+		if (lower_size_after_truncate < lower_size_before_truncate)
+			vmtruncate(lower_dentry->d_inode,
+				   lower_size_after_truncate);
+	}
+	/* Update the access times */
+	lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime
+		= CURRENT_TIME;
+	mark_inode_dirty_sync(inode);
+out_fput:
+	fput(lower_file);
+out_free:
+	if (ecryptfs_file_to_private(&fake_ecryptfs_file))
+		kmem_cache_free(ecryptfs_file_info_cache,
+				ecryptfs_file_to_private(&fake_ecryptfs_file));
+out:
+	return rc;
+}
+
+static int
+ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+	int rc;
+
+        if (nd) {
+		struct vfsmount *vfsmnt_save = nd->mnt;
+		struct dentry *dentry_save = nd->dentry;
+
+		nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry);
+		nd->dentry = ecryptfs_dentry_to_lower(nd->dentry);
+		rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
+		nd->mnt = vfsmnt_save;
+		nd->dentry = dentry_save;
+        } else
+		rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
+        return rc;
+}
+
+/**
+ * ecryptfs_setattr
+ * @dentry: dentry handle to the inode to modify
+ * @ia: Structure with flags of what to change and values
+ *
+ * Updates the metadata of an inode. If the update is to the size
+ * i.e. truncation, then ecryptfs_truncate will handle the size modification
+ * of both the ecryptfs inode and the lower inode.
+ *
+ * All other metadata changes will be passed right to the lower filesystem,
+ * and we will just update our inode to look like the lower.
+ */
+static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+	int rc = 0;
+	struct dentry *lower_dentry;
+	struct inode *inode;
+	struct inode *lower_inode;
+	struct ecryptfs_crypt_stat *crypt_stat;
+
+	crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	inode = dentry->d_inode;
+	lower_inode = ecryptfs_inode_to_lower(inode);
+	if (ia->ia_valid & ATTR_SIZE) {
+		ecryptfs_printk(KERN_DEBUG,
+				"ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",
+				ia->ia_valid, ATTR_SIZE);
+		rc = ecryptfs_truncate(dentry, ia->ia_size);
+		/* ecryptfs_truncate handles resizing of the lower file */
+		ia->ia_valid &= ~ATTR_SIZE;
+		ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n",
+				ia->ia_valid);
+		if (rc < 0)
+			goto out;
+	}
+	rc = notify_change(lower_dentry, ia);
+out:
+	ecryptfs_copy_attr_all(inode, lower_inode);
+	return rc;
+}
+
+static int
+ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+		  size_t size, int flags)
+{
+	int rc = 0;
+	struct dentry *lower_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	if (!lower_dentry->d_inode->i_op->setxattr) {
+		rc = -ENOSYS;
+		goto out;
+	}
+	mutex_lock(&lower_dentry->d_inode->i_mutex);
+	rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value,
+						   size, flags);
+	mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+	return rc;
+}
+
+static ssize_t
+ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
+		  size_t size)
+{
+	int rc = 0;
+	struct dentry *lower_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	if (!lower_dentry->d_inode->i_op->getxattr) {
+		rc = -ENOSYS;
+		goto out;
+	}
+	mutex_lock(&lower_dentry->d_inode->i_mutex);
+	rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value,
+						   size);
+	mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+	return rc;
+}
+
+static ssize_t
+ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+	int rc = 0;
+	struct dentry *lower_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	if (!lower_dentry->d_inode->i_op->listxattr) {
+		rc = -ENOSYS;
+		goto out;
+	}
+	mutex_lock(&lower_dentry->d_inode->i_mutex);
+	rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size);
+	mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+	return rc;
+}
+
+static int ecryptfs_removexattr(struct dentry *dentry, const char *name)
+{
+	int rc = 0;
+	struct dentry *lower_dentry;
+
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	if (!lower_dentry->d_inode->i_op->removexattr) {
+		rc = -ENOSYS;
+		goto out;
+	}
+	mutex_lock(&lower_dentry->d_inode->i_mutex);
+	rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name);
+	mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+	return rc;
+}
+
+int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode)
+{
+	if ((ecryptfs_inode_to_lower(inode)
+	     == (struct inode *)candidate_lower_inode))
+		return 1;
+	else
+		return 0;
+}
+
+int ecryptfs_inode_set(struct inode *inode, void *lower_inode)
+{
+	ecryptfs_init_inode(inode, (struct inode *)lower_inode);
+	return 0;
+}
+
+struct inode_operations ecryptfs_symlink_iops = {
+	.readlink = ecryptfs_readlink,
+	.follow_link = ecryptfs_follow_link,
+	.put_link = ecryptfs_put_link,
+	.permission = ecryptfs_permission,
+	.setattr = ecryptfs_setattr,
+	.setxattr = ecryptfs_setxattr,
+	.getxattr = ecryptfs_getxattr,
+	.listxattr = ecryptfs_listxattr,
+	.removexattr = ecryptfs_removexattr
+};
+
+struct inode_operations ecryptfs_dir_iops = {
+	.create = ecryptfs_create,
+	.lookup = ecryptfs_lookup,
+	.link = ecryptfs_link,
+	.unlink = ecryptfs_unlink,
+	.symlink = ecryptfs_symlink,
+	.mkdir = ecryptfs_mkdir,
+	.rmdir = ecryptfs_rmdir,
+	.mknod = ecryptfs_mknod,
+	.rename = ecryptfs_rename,
+	.permission = ecryptfs_permission,
+	.setattr = ecryptfs_setattr,
+	.setxattr = ecryptfs_setxattr,
+	.getxattr = ecryptfs_getxattr,
+	.listxattr = ecryptfs_listxattr,
+	.removexattr = ecryptfs_removexattr
+};
+
+struct inode_operations ecryptfs_main_iops = {
+	.permission = ecryptfs_permission,
+	.setattr = ecryptfs_setattr,
+	.setxattr = ecryptfs_setxattr,
+	.getxattr = ecryptfs_getxattr,
+	.listxattr = ecryptfs_listxattr,
+	.removexattr = ecryptfs_removexattr
+};
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
new file mode 100644
index 0000000..ba45478
--- /dev/null
+++ b/fs/ecryptfs/keystore.c
@@ -0,0 +1,1061 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * In-kernel key management code.  Includes functions to parse and
+ * write authentication token-related packets with the underlying
+ * file.
+ *
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ *              Michael C. Thompson <mcthomps@us.ibm.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 <linux/string.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * request_key returned an error instead of a valid key address;
+ * determine the type of error, make appropriate log entries, and
+ * return an error code.
+ */
+int process_request_key_err(long err_code)
+{
+	int rc = 0;
+
+	switch (err_code) {
+	case ENOKEY:
+		ecryptfs_printk(KERN_WARNING, "No key\n");
+		rc = -ENOENT;
+		break;
+	case EKEYEXPIRED:
+		ecryptfs_printk(KERN_WARNING, "Key expired\n");
+		rc = -ETIME;
+		break;
+	case EKEYREVOKED:
+		ecryptfs_printk(KERN_WARNING, "Key revoked\n");
+		rc = -EINVAL;
+		break;
+	default:
+		ecryptfs_printk(KERN_WARNING, "Unknown error code: "
+				"[0x%.16x]\n", err_code);
+		rc = -EINVAL;
+	}
+	return rc;
+}
+
+static void wipe_auth_tok_list(struct list_head *auth_tok_list_head)
+{
+	struct list_head *walker;
+	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+
+	walker = auth_tok_list_head->next;
+	while (walker != auth_tok_list_head) {
+		auth_tok_list_item =
+		    list_entry(walker, struct ecryptfs_auth_tok_list_item,
+			       list);
+		walker = auth_tok_list_item->list.next;
+		memset(auth_tok_list_item, 0,
+		       sizeof(struct ecryptfs_auth_tok_list_item));
+		kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+				auth_tok_list_item);
+	}
+}
+
+struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
+
+/**
+ * parse_packet_length
+ * @data: Pointer to memory containing length at offset
+ * @size: This function writes the decoded size to this memory
+ *        address; zero on error
+ * @length_size: The number of bytes occupied by the encoded length
+ *
+ * Returns Zero on success
+ */
+static int parse_packet_length(unsigned char *data, size_t *size,
+			       size_t *length_size)
+{
+	int rc = 0;
+
+	(*length_size) = 0;
+	(*size) = 0;
+	if (data[0] < 192) {
+		/* One-byte length */
+		(*size) = data[0];
+		(*length_size) = 1;
+	} else if (data[0] < 224) {
+		/* Two-byte length */
+		(*size) = ((data[0] - 192) * 256);
+		(*size) += (data[1] + 192);
+		(*length_size) = 2;
+	} else if (data[0] == 255) {
+		/* Five-byte length; we're not supposed to see this */
+		ecryptfs_printk(KERN_ERR, "Five-byte packet length not "
+				"supported\n");
+		rc = -EINVAL;
+		goto out;
+	} else {
+		ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");
+		rc = -EINVAL;
+		goto out;
+	}
+out:
+	return rc;
+}
+
+/**
+ * write_packet_length
+ * @dest: The byte array target into which to write the
+ *       length. Must have at least 5 bytes allocated.
+ * @size: The length to write.
+ * @packet_size_length: The number of bytes used to encode the
+ *                      packet length is written to this address.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int write_packet_length(char *dest, size_t size,
+			       size_t *packet_size_length)
+{
+	int rc = 0;
+
+	if (size < 192) {
+		dest[0] = size;
+		(*packet_size_length) = 1;
+	} else if (size < 65536) {
+		dest[0] = (((size - 192) / 256) + 192);
+		dest[1] = ((size - 192) % 256);
+		(*packet_size_length) = 2;
+	} else {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_WARNING,
+				"Unsupported packet size: [%d]\n", size);
+	}
+	return rc;
+}
+
+/**
+ * parse_tag_3_packet
+ * @crypt_stat: The cryptographic context to modify based on packet
+ *              contents.
+ * @data: The raw bytes of the packet.
+ * @auth_tok_list: eCryptfs parses packets into authentication tokens;
+ *                 a new authentication token will be placed at the end
+ *                 of this list for this packet.
+ * @new_auth_tok: Pointer to a pointer to memory that this function
+ *                allocates; sets the memory address of the pointer to
+ *                NULL on error. This object is added to the
+ *                auth_tok_list.
+ * @packet_size: This function writes the size of the parsed packet
+ *               into this memory location; zero on error.
+ * @max_packet_size: maximum number of bytes to parse
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
+		   unsigned char *data, struct list_head *auth_tok_list,
+		   struct ecryptfs_auth_tok **new_auth_tok,
+		   size_t *packet_size, size_t max_packet_size)
+{
+	int rc = 0;
+	size_t body_size;
+	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+	size_t length_size;
+
+	(*packet_size) = 0;
+	(*new_auth_tok) = NULL;
+
+	/* we check that:
+	 *   one byte for the Tag 3 ID flag
+	 *   two bytes for the body size
+	 * do not exceed the maximum_packet_size
+	 */
+	if (unlikely((*packet_size) + 3 > max_packet_size)) {
+		ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* check for Tag 3 identifyer - one byte */
+	if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {
+		ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n",
+				ECRYPTFS_TAG_3_PACKET_TYPE);
+		rc = -EINVAL;
+		goto out;
+	}
+	/* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
+	 * at end of function upon failure */
+	auth_tok_list_item =
+	    kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, SLAB_KERNEL);
+	if (!auth_tok_list_item) {
+		ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(auth_tok_list_item, 0,
+	       sizeof(struct ecryptfs_auth_tok_list_item));
+	(*new_auth_tok) = &auth_tok_list_item->auth_tok;
+
+	/* check for body size - one to two bytes */
+	rc = parse_packet_length(&data[(*packet_size)], &body_size,
+				 &length_size);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
+				"rc = [%d]\n", rc);
+		goto out_free;
+	}
+	if (unlikely(body_size < (0x05 + ECRYPTFS_SALT_SIZE))) {
+		ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
+				body_size);
+		rc = -EINVAL;
+		goto out_free;
+	}
+	(*packet_size) += length_size;
+
+	/* now we know the length of the remainting Tag 3 packet size:
+	 *   5 fix bytes for: version string, cipher, S2K ID, hash algo,
+	 *                    number of hash iterations
+	 *   ECRYPTFS_SALT_SIZE bytes for salt
+	 *   body_size bytes minus the stuff above is the encrypted key size
+	 */
+	if (unlikely((*packet_size) + body_size > max_packet_size)) {
+		ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+		rc = -EINVAL;
+		goto out_free;
+	}
+
+	/* There are 5 characters of additional information in the
+	 * packet */
+	(*new_auth_tok)->session_key.encrypted_key_size =
+		body_size - (0x05 + ECRYPTFS_SALT_SIZE);
+	ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n",
+			(*new_auth_tok)->session_key.encrypted_key_size);
+
+	/* Version 4 (from RFC2440) - one byte */
+	if (unlikely(data[(*packet_size)++] != 0x04)) {
+		ecryptfs_printk(KERN_DEBUG, "Unknown version number "
+				"[%d]\n", data[(*packet_size) - 1]);
+		rc = -EINVAL;
+		goto out_free;
+	}
+
+	/* cipher - one byte */
+	ecryptfs_cipher_code_to_string(crypt_stat->cipher,
+				       (u16)data[(*packet_size)]);
+	/* A little extra work to differentiate among the AES key
+	 * sizes; see RFC2440 */
+	switch(data[(*packet_size)++]) {
+	case RFC2440_CIPHER_AES_192:
+		crypt_stat->key_size = 24;
+		break;
+	default:
+		crypt_stat->key_size =
+			(*new_auth_tok)->session_key.encrypted_key_size;
+	}
+	ecryptfs_init_crypt_ctx(crypt_stat);
+	/* S2K identifier 3 (from RFC2440) */
+	if (unlikely(data[(*packet_size)++] != 0x03)) {
+		ecryptfs_printk(KERN_ERR, "Only S2K ID 3 is currently "
+				"supported\n");
+		rc = -ENOSYS;
+		goto out_free;
+	}
+
+	/* TODO: finish the hash mapping */
+	/* hash algorithm - one byte */
+	switch (data[(*packet_size)++]) {
+	case 0x01: /* See RFC2440 for these numbers and their mappings */
+		/* Choose MD5 */
+		/* salt - ECRYPTFS_SALT_SIZE bytes */
+		memcpy((*new_auth_tok)->token.password.salt,
+		       &data[(*packet_size)], ECRYPTFS_SALT_SIZE);
+		(*packet_size) += ECRYPTFS_SALT_SIZE;
+
+		/* This conversion was taken straight from RFC2440 */
+		/* number of hash iterations - one byte */
+		(*new_auth_tok)->token.password.hash_iterations =
+			((u32) 16 + (data[(*packet_size)] & 15))
+				<< ((data[(*packet_size)] >> 4) + 6);
+		(*packet_size)++;
+
+		/* encrypted session key -
+		 *   (body_size-5-ECRYPTFS_SALT_SIZE) bytes */
+		memcpy((*new_auth_tok)->session_key.encrypted_key,
+		       &data[(*packet_size)],
+		       (*new_auth_tok)->session_key.encrypted_key_size);
+		(*packet_size) +=
+			(*new_auth_tok)->session_key.encrypted_key_size;
+		(*new_auth_tok)->session_key.flags &=
+			~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+		(*new_auth_tok)->session_key.flags |=
+			ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
+		(*new_auth_tok)->token.password.hash_algo = 0x01;
+		break;
+	default:
+		ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: "
+				"[%d]\n", data[(*packet_size) - 1]);
+		rc = -ENOSYS;
+		goto out_free;
+	}
+	(*new_auth_tok)->token_type = ECRYPTFS_PASSWORD;
+	/* TODO: Parametarize; we might actually want userspace to
+	 * decrypt the session key. */
+	ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
+			    ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
+	ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
+			    ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
+	list_add(&auth_tok_list_item->list, auth_tok_list);
+	goto out;
+out_free:
+	(*new_auth_tok) = NULL;
+	memset(auth_tok_list_item, 0,
+	       sizeof(struct ecryptfs_auth_tok_list_item));
+	kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+			auth_tok_list_item);
+out:
+	if (rc)
+		(*packet_size) = 0;
+	return rc;
+}
+
+/**
+ * parse_tag_11_packet
+ * @data: The raw bytes of the packet
+ * @contents: This function writes the data contents of the literal
+ *            packet into this memory location
+ * @max_contents_bytes: The maximum number of bytes that this function
+ *                      is allowed to write into contents
+ * @tag_11_contents_size: This function writes the size of the parsed
+ *                        contents into this memory location; zero on
+ *                        error
+ * @packet_size: This function writes the size of the parsed packet
+ *               into this memory location; zero on error
+ * @max_packet_size: maximum number of bytes to parse
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+parse_tag_11_packet(unsigned char *data, unsigned char *contents,
+		    size_t max_contents_bytes, size_t *tag_11_contents_size,
+		    size_t *packet_size, size_t max_packet_size)
+{
+	int rc = 0;
+	size_t body_size;
+	size_t length_size;
+
+	(*packet_size) = 0;
+	(*tag_11_contents_size) = 0;
+
+	/* check that:
+	 *   one byte for the Tag 11 ID flag
+	 *   two bytes for the Tag 11 length
+	 * do not exceed the maximum_packet_size
+	 */
+	if (unlikely((*packet_size) + 3 > max_packet_size)) {
+		ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* check for Tag 11 identifyer - one byte */
+	if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) {
+		ecryptfs_printk(KERN_WARNING,
+				"Invalid tag 11 packet format\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* get Tag 11 content length - one or two bytes */
+	rc = parse_packet_length(&data[(*packet_size)], &body_size,
+				 &length_size);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING,
+				"Invalid tag 11 packet format\n");
+		goto out;
+	}
+	(*packet_size) += length_size;
+
+	if (body_size < 13) {
+		ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
+				body_size);
+		rc = -EINVAL;
+		goto out;
+	}
+	/* We have 13 bytes of surrounding packet values */
+	(*tag_11_contents_size) = (body_size - 13);
+
+	/* now we know the length of the remainting Tag 11 packet size:
+	 *   14 fix bytes for: special flag one, special flag two,
+	 *   		       12 skipped bytes
+	 *   body_size bytes minus the stuff above is the Tag 11 content
+	 */
+	/* FIXME why is the body size one byte smaller than the actual
+	 * size of the body?
+	 * this seems to be an error here as well as in
+	 * write_tag_11_packet() */
+	if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
+		ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* special flag one - one byte */
+	if (data[(*packet_size)++] != 0x62) {
+		ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* special flag two - one byte */
+	if (data[(*packet_size)++] != 0x08) {
+		ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* skip the next 12 bytes */
+	(*packet_size) += 12; /* We don't care about the filename or
+			       * the timestamp */
+
+	/* get the Tag 11 contents - tag_11_contents_size bytes */
+	memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size));
+	(*packet_size) += (*tag_11_contents_size);
+
+out:
+	if (rc) {
+		(*packet_size) = 0;
+		(*tag_11_contents_size) = 0;
+	}
+	return rc;
+}
+
+/**
+ * decrypt_session_key - Decrypt the session key with the given auth_tok.
+ *
+ * Returns Zero on success; non-zero error otherwise.
+ */
+static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
+			       struct ecryptfs_crypt_stat *crypt_stat)
+{
+	int rc = 0;
+	struct ecryptfs_password *password_s_ptr;
+	struct crypto_tfm *tfm = NULL;
+	struct scatterlist src_sg[2], dst_sg[2];
+	struct mutex *tfm_mutex = NULL;
+	/* TODO: Use virt_to_scatterlist for these */
+	char *encrypted_session_key;
+	char *session_key;
+
+	password_s_ptr = &auth_tok->token.password;
+	if (ECRYPTFS_CHECK_FLAG(password_s_ptr->flags,
+				ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET))
+		ecryptfs_printk(KERN_DEBUG, "Session key encryption key "
+				"set; skipping key generation\n");
+	ecryptfs_printk(KERN_DEBUG, "Session key encryption key (size [%d])"
+			":\n",
+			password_s_ptr->session_key_encryption_key_bytes);
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(password_s_ptr->session_key_encryption_key,
+				  password_s_ptr->
+				  session_key_encryption_key_bytes);
+	if (!strcmp(crypt_stat->cipher,
+		    crypt_stat->mount_crypt_stat->global_default_cipher_name)
+	    && crypt_stat->mount_crypt_stat->global_key_tfm) {
+		tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
+		tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
+	} else {
+		tfm = crypto_alloc_tfm(crypt_stat->cipher,
+				       CRYPTO_TFM_REQ_WEAK_KEY);
+		if (!tfm) {
+			printk(KERN_ERR "Error allocating crypto context\n");
+			rc = -ENOMEM;
+			goto out;
+		}
+	}
+	if (password_s_ptr->session_key_encryption_key_bytes
+	    < crypto_tfm_alg_min_keysize(tfm)) {
+		printk(KERN_WARNING "Session key encryption key is [%d] bytes; "
+		       "minimum keysize for selected cipher is [%d] bytes.\n",
+		       password_s_ptr->session_key_encryption_key_bytes,
+		       crypto_tfm_alg_min_keysize(tfm));
+		rc = -EINVAL;
+		goto out;
+	}
+	if (tfm_mutex)
+		mutex_lock(tfm_mutex);
+	crypto_cipher_setkey(tfm, password_s_ptr->session_key_encryption_key,
+			     crypt_stat->key_size);
+	/* TODO: virt_to_scatterlist */
+	encrypted_session_key = (char *)__get_free_page(GFP_KERNEL);
+	if (!encrypted_session_key) {
+		ecryptfs_printk(KERN_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto out_free_tfm;
+	}
+	session_key = (char *)__get_free_page(GFP_KERNEL);
+	if (!session_key) {
+		kfree(encrypted_session_key);
+		ecryptfs_printk(KERN_ERR, "Out of memory\n");
+		rc = -ENOMEM;
+		goto out_free_tfm;
+	}
+	memcpy(encrypted_session_key, auth_tok->session_key.encrypted_key,
+	       auth_tok->session_key.encrypted_key_size);
+	src_sg[0].page = virt_to_page(encrypted_session_key);
+	src_sg[0].offset = 0;
+	BUG_ON(auth_tok->session_key.encrypted_key_size > PAGE_CACHE_SIZE);
+	src_sg[0].length = auth_tok->session_key.encrypted_key_size;
+	dst_sg[0].page = virt_to_page(session_key);
+	dst_sg[0].offset = 0;
+	auth_tok->session_key.decrypted_key_size =
+	    auth_tok->session_key.encrypted_key_size;
+	dst_sg[0].length = auth_tok->session_key.encrypted_key_size;
+	/* TODO: Handle error condition */
+	crypto_cipher_decrypt(tfm, dst_sg, src_sg,
+			      auth_tok->session_key.encrypted_key_size);
+	auth_tok->session_key.decrypted_key_size =
+	    auth_tok->session_key.encrypted_key_size;
+	memcpy(auth_tok->session_key.decrypted_key, session_key,
+	       auth_tok->session_key.decrypted_key_size);
+	auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+	memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
+	       auth_tok->session_key.decrypted_key_size);
+	ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+	ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex(crypt_stat->key,
+				  crypt_stat->key_size);
+	memset(encrypted_session_key, 0, PAGE_CACHE_SIZE);
+	free_page((unsigned long)encrypted_session_key);
+	memset(session_key, 0, PAGE_CACHE_SIZE);
+	free_page((unsigned long)session_key);
+out_free_tfm:
+	if (tfm_mutex)
+		mutex_unlock(tfm_mutex);
+	else
+		crypto_free_tfm(tfm);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_parse_packet_set
+ * @dest: The header page in memory
+ * @version: Version of file format, to guide parsing behavior
+ *
+ * Get crypt_stat to have the file's session key if the requisite key
+ * is available to decrypt the session key.
+ *
+ * Returns Zero if a valid authentication token was retrieved and
+ * processed; negative value for file not encrypted or for error
+ * conditions.
+ */
+int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
+			      unsigned char *src,
+			      struct dentry *ecryptfs_dentry)
+{
+	size_t i = 0;
+	int rc = 0;
+	size_t found_auth_tok = 0;
+	size_t next_packet_is_auth_tok_packet;
+	char sig[ECRYPTFS_SIG_SIZE_HEX];
+	struct list_head auth_tok_list;
+	struct list_head *walker;
+	struct ecryptfs_auth_tok *chosen_auth_tok = NULL;
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+		&ecryptfs_superblock_to_private(
+			ecryptfs_dentry->d_sb)->mount_crypt_stat;
+	struct ecryptfs_auth_tok *candidate_auth_tok = NULL;
+	size_t packet_size;
+	struct ecryptfs_auth_tok *new_auth_tok;
+	unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE];
+	size_t tag_11_contents_size;
+	size_t tag_11_packet_size;
+
+	INIT_LIST_HEAD(&auth_tok_list);
+	/* Parse the header to find as many packets as we can, these will be
+	 * added the our &auth_tok_list */
+	next_packet_is_auth_tok_packet = 1;
+	while (next_packet_is_auth_tok_packet) {
+		size_t max_packet_size = ((PAGE_CACHE_SIZE - 8) - i);
+
+		switch (src[i]) {
+		case ECRYPTFS_TAG_3_PACKET_TYPE:
+			rc = parse_tag_3_packet(crypt_stat,
+						(unsigned char *)&src[i],
+						&auth_tok_list, &new_auth_tok,
+						&packet_size, max_packet_size);
+			if (rc) {
+				ecryptfs_printk(KERN_ERR, "Error parsing "
+						"tag 3 packet\n");
+				rc = -EIO;
+				goto out_wipe_list;
+			}
+			i += packet_size;
+			rc = parse_tag_11_packet((unsigned char *)&src[i],
+						 sig_tmp_space,
+						 ECRYPTFS_SIG_SIZE,
+						 &tag_11_contents_size,
+						 &tag_11_packet_size,
+						 max_packet_size);
+			if (rc) {
+				ecryptfs_printk(KERN_ERR, "No valid "
+						"(ecryptfs-specific) literal "
+						"packet containing "
+						"authentication token "
+						"signature found after "
+						"tag 3 packet\n");
+				rc = -EIO;
+				goto out_wipe_list;
+			}
+			i += tag_11_packet_size;
+			if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
+				ecryptfs_printk(KERN_ERR, "Expected "
+						"signature of size [%d]; "
+						"read size [%d]\n",
+						ECRYPTFS_SIG_SIZE,
+						tag_11_contents_size);
+				rc = -EIO;
+				goto out_wipe_list;
+			}
+			ecryptfs_to_hex(new_auth_tok->token.password.signature,
+					sig_tmp_space, tag_11_contents_size);
+			new_auth_tok->token.password.signature[
+				ECRYPTFS_PASSWORD_SIG_SIZE] = '\0';
+			ECRYPTFS_SET_FLAG(crypt_stat->flags,
+					  ECRYPTFS_ENCRYPTED);
+			break;
+		case ECRYPTFS_TAG_11_PACKET_TYPE:
+			ecryptfs_printk(KERN_WARNING, "Invalid packet set "
+					"(Tag 11 not allowed by itself)\n");
+			rc = -EIO;
+			goto out_wipe_list;
+			break;
+		default:
+			ecryptfs_printk(KERN_DEBUG, "No packet at offset "
+					"[%d] of the file header; hex value of "
+					"character is [0x%.2x]\n", i, src[i]);
+			next_packet_is_auth_tok_packet = 0;
+		}
+	}
+	if (list_empty(&auth_tok_list)) {
+		rc = -EINVAL; /* Do not support non-encrypted files in
+			       * the 0.1 release */
+		goto out;
+	}
+	/* If we have a global auth tok, then we should try to use
+	 * it */
+	if (mount_crypt_stat->global_auth_tok) {
+		memcpy(sig, mount_crypt_stat->global_auth_tok_sig,
+		       ECRYPTFS_SIG_SIZE_HEX);
+		chosen_auth_tok = mount_crypt_stat->global_auth_tok;
+	} else
+		BUG(); /* We should always have a global auth tok in
+			* the 0.1 release */
+	/* Scan list to see if our chosen_auth_tok works */
+	list_for_each(walker, &auth_tok_list) {
+		struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+		auth_tok_list_item =
+		    list_entry(walker, struct ecryptfs_auth_tok_list_item,
+			       list);
+		candidate_auth_tok = &auth_tok_list_item->auth_tok;
+		if (unlikely(ecryptfs_verbosity > 0)) {
+			ecryptfs_printk(KERN_DEBUG,
+					"Considering cadidate auth tok:\n");
+			ecryptfs_dump_auth_tok(candidate_auth_tok);
+		}
+		/* TODO: Replace ECRYPTFS_SIG_SIZE_HEX w/ dynamic value */
+		if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD
+		    && !strncmp(candidate_auth_tok->token.password.signature,
+				sig, ECRYPTFS_SIG_SIZE_HEX)) {
+			found_auth_tok = 1;
+			goto leave_list;
+			/* TODO: Transfer the common salt into the
+			 * crypt_stat salt */
+		}
+	}
+leave_list:
+	if (!found_auth_tok) {
+		ecryptfs_printk(KERN_ERR, "Could not find authentication "
+				"token on temporary list for sig [%.*s]\n",
+				ECRYPTFS_SIG_SIZE_HEX, sig);
+		rc = -EIO;
+		goto out_wipe_list;
+	} else {
+		memcpy(&(candidate_auth_tok->token.password),
+		       &(chosen_auth_tok->token.password),
+		       sizeof(struct ecryptfs_password));
+		rc = decrypt_session_key(candidate_auth_tok, crypt_stat);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error decrypting the "
+					"session key\n");
+			goto out_wipe_list;
+		}
+		rc = ecryptfs_compute_root_iv(crypt_stat);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error computing "
+					"the root IV\n");
+			goto out_wipe_list;
+		}
+	}
+	rc = ecryptfs_init_crypt_ctx(crypt_stat);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error initializing crypto "
+				"context for cipher [%s]; rc = [%d]\n",
+				crypt_stat->cipher, rc);
+	}
+out_wipe_list:
+	wipe_auth_tok_list(&auth_tok_list);
+out:
+	return rc;
+}
+
+/**
+ * write_tag_11_packet
+ * @dest: Target into which Tag 11 packet is to be written
+ * @max: Maximum packet length
+ * @contents: Byte array of contents to copy in
+ * @contents_length: Number of bytes in contents
+ * @packet_length: Length of the Tag 11 packet written; zero on error
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length,
+		    size_t *packet_length)
+{
+	int rc = 0;
+	size_t packet_size_length;
+
+	(*packet_length) = 0;
+	if ((13 + contents_length) > max) {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_ERR, "Packet length larger than "
+				"maximum allowable\n");
+		goto out;
+	}
+	/* General packet header */
+	/* Packet tag */
+	dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
+	/* Packet length */
+	rc = write_packet_length(&dest[(*packet_length)],
+				 (13 + contents_length), &packet_size_length);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error generating tag 11 packet "
+				"header; cannot generate packet length\n");
+		goto out;
+	}
+	(*packet_length) += packet_size_length;
+	/* Tag 11 specific */
+	/* One-octet field that describes how the data is formatted */
+	dest[(*packet_length)++] = 0x62; /* binary data */
+	/* One-octet filename length followed by filename */
+	dest[(*packet_length)++] = 8;
+	memcpy(&dest[(*packet_length)], "_CONSOLE", 8);
+	(*packet_length) += 8;
+	/* Four-octet number indicating modification date */
+	memset(&dest[(*packet_length)], 0x00, 4);
+	(*packet_length) += 4;
+	/* Remainder is literal data */
+	memcpy(&dest[(*packet_length)], contents, contents_length);
+	(*packet_length) += contents_length;
+ out:
+	if (rc)
+		(*packet_length) = 0;
+	return rc;
+}
+
+/**
+ * write_tag_3_packet
+ * @dest: Buffer into which to write the packet
+ * @max: Maximum number of bytes that can be written
+ * @auth_tok: Authentication token
+ * @crypt_stat: The cryptographic context
+ * @key_rec: encrypted key
+ * @packet_size: This function will write the number of bytes that end
+ *               up constituting the packet; set to zero on error
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok,
+		   struct ecryptfs_crypt_stat *crypt_stat,
+		   struct ecryptfs_key_record *key_rec, size_t *packet_size)
+{
+	int rc = 0;
+
+	size_t i;
+	size_t signature_is_valid = 0;
+	size_t encrypted_session_key_valid = 0;
+	char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+	struct scatterlist dest_sg[2];
+	struct scatterlist src_sg[2];
+	struct crypto_tfm *tfm = NULL;
+	struct mutex *tfm_mutex = NULL;
+	size_t key_rec_size;
+	size_t packet_size_length;
+	size_t cipher_code;
+
+	(*packet_size) = 0;
+	/* Check for a valid signature on the auth_tok */
+	for (i = 0; i < ECRYPTFS_SIG_SIZE_HEX; i++)
+		signature_is_valid |= auth_tok->token.password.signature[i];
+	if (!signature_is_valid)
+		BUG();
+	ecryptfs_from_hex((*key_rec).sig, auth_tok->token.password.signature,
+			  ECRYPTFS_SIG_SIZE);
+	encrypted_session_key_valid = 0;
+	for (i = 0; i < crypt_stat->key_size; i++)
+		encrypted_session_key_valid |=
+			auth_tok->session_key.encrypted_key[i];
+	if (encrypted_session_key_valid) {
+		memcpy((*key_rec).enc_key,
+		       auth_tok->session_key.encrypted_key,
+		       auth_tok->session_key.encrypted_key_size);
+		goto encrypted_session_key_set;
+	}
+	if (auth_tok->session_key.encrypted_key_size == 0)
+		auth_tok->session_key.encrypted_key_size =
+			crypt_stat->key_size;
+	if (crypt_stat->key_size == 24
+	    && strcmp("aes", crypt_stat->cipher) == 0) {
+		memset((crypt_stat->key + 24), 0, 8);
+		auth_tok->session_key.encrypted_key_size = 32;
+	}
+	(*key_rec).enc_key_size =
+		auth_tok->session_key.encrypted_key_size;
+	if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
+				ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) {
+		ecryptfs_printk(KERN_DEBUG, "Using previously generated "
+				"session key encryption key of size [%d]\n",
+				auth_tok->token.password.
+				session_key_encryption_key_bytes);
+		memcpy(session_key_encryption_key,
+		       auth_tok->token.password.session_key_encryption_key,
+		       crypt_stat->key_size);
+		ecryptfs_printk(KERN_DEBUG,
+				"Cached session key " "encryption key: \n");
+		if (ecryptfs_verbosity > 0)
+			ecryptfs_dump_hex(session_key_encryption_key, 16);
+	}
+	if (unlikely(ecryptfs_verbosity > 0)) {
+		ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n");
+		ecryptfs_dump_hex(session_key_encryption_key, 16);
+	}
+	rc = virt_to_scatterlist(crypt_stat->key,
+				 (*key_rec).enc_key_size, src_sg, 2);
+	if (!rc) {
+		ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+				"for crypt_stat session key\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	rc = virt_to_scatterlist((*key_rec).enc_key,
+				 (*key_rec).enc_key_size, dest_sg, 2);
+	if (!rc) {
+		ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+				"for crypt_stat encrypted session key\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	if (!strcmp(crypt_stat->cipher,
+		    crypt_stat->mount_crypt_stat->global_default_cipher_name)
+	    && crypt_stat->mount_crypt_stat->global_key_tfm) {
+		tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
+		tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
+	} else
+		tfm = crypto_alloc_tfm(crypt_stat->cipher, 0);
+	if (!tfm) {
+		ecryptfs_printk(KERN_ERR, "Could not initialize crypto "
+				"context for cipher [%s]\n",
+				crypt_stat->cipher);
+		rc = -EINVAL;
+		goto out;
+	}
+	if (tfm_mutex)
+		mutex_lock(tfm_mutex);
+	rc = crypto_cipher_setkey(tfm, session_key_encryption_key,
+				  crypt_stat->key_size);
+	if (rc < 0) {
+		if (tfm_mutex)
+			mutex_unlock(tfm_mutex);
+		ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
+				"context\n");
+		goto out;
+	}
+	rc = 0;
+	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
+			crypt_stat->key_size);
+	crypto_cipher_encrypt(tfm, dest_sg, src_sg,
+			      (*key_rec).enc_key_size);
+	if (tfm_mutex)
+		mutex_unlock(tfm_mutex);
+	ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n");
+	if (ecryptfs_verbosity > 0)
+		ecryptfs_dump_hex((*key_rec).enc_key,
+				  (*key_rec).enc_key_size);
+encrypted_session_key_set:
+	/* Now we have a valid key_rec.  Append it to the
+	 * key_rec set. */
+	key_rec_size = (sizeof(struct ecryptfs_key_record)
+			- ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES
+			+ ((*key_rec).enc_key_size));
+	/* TODO: Include a packet size limit as a parameter to this
+	 * function once we have multi-packet headers (for versions
+	 * later than 0.1 */
+	if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) {
+		ecryptfs_printk(KERN_ERR, "Keyset too large\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	/* TODO: Packet size limit */
+	/* We have 5 bytes of surrounding packet data */
+	if ((0x05 + ECRYPTFS_SALT_SIZE
+	     + (*key_rec).enc_key_size) >= max) {
+		ecryptfs_printk(KERN_ERR, "Authentication token is too "
+				"large\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	/* This format is inspired by OpenPGP; see RFC 2440
+	 * packet tag 3 */
+	dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
+	/* ver+cipher+s2k+hash+salt+iter+enc_key */
+	rc = write_packet_length(&dest[(*packet_size)],
+				 (0x05 + ECRYPTFS_SALT_SIZE
+				  + (*key_rec).enc_key_size),
+				 &packet_size_length);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error generating tag 3 packet "
+				"header; cannot generate packet length\n");
+		goto out;
+	}
+	(*packet_size) += packet_size_length;
+	dest[(*packet_size)++] = 0x04; /* version 4 */
+	cipher_code = ecryptfs_code_for_cipher_string(crypt_stat);
+	if (cipher_code == 0) {
+		ecryptfs_printk(KERN_WARNING, "Unable to generate code for "
+				"cipher [%s]\n", crypt_stat->cipher);
+		rc = -EINVAL;
+		goto out;
+	}
+	dest[(*packet_size)++] = cipher_code;
+	dest[(*packet_size)++] = 0x03;	/* S2K */
+	dest[(*packet_size)++] = 0x01;	/* MD5 (TODO: parameterize) */
+	memcpy(&dest[(*packet_size)], auth_tok->token.password.salt,
+	       ECRYPTFS_SALT_SIZE);
+	(*packet_size) += ECRYPTFS_SALT_SIZE;	/* salt */
+	dest[(*packet_size)++] = 0x60;	/* hash iterations (65536) */
+	memcpy(&dest[(*packet_size)], (*key_rec).enc_key,
+	       (*key_rec).enc_key_size);
+	(*packet_size) += (*key_rec).enc_key_size;
+out:
+	if (tfm && !tfm_mutex)
+		crypto_free_tfm(tfm);
+	if (rc)
+		(*packet_size) = 0;
+	return rc;
+}
+
+/**
+ * ecryptfs_generate_key_packet_set
+ * @dest: Virtual address from which to write the key record set
+ * @crypt_stat: The cryptographic context from which the
+ *              authentication tokens will be retrieved
+ * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat
+ *                   for the global parameters
+ * @len: The amount written
+ * @max: The maximum amount of data allowed to be written
+ *
+ * Generates a key packet set and writes it to the virtual address
+ * passed in.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+int
+ecryptfs_generate_key_packet_set(char *dest_base,
+				 struct ecryptfs_crypt_stat *crypt_stat,
+				 struct dentry *ecryptfs_dentry, size_t *len,
+				 size_t max)
+{
+	int rc = 0;
+	struct ecryptfs_auth_tok *auth_tok;
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+		&ecryptfs_superblock_to_private(
+			ecryptfs_dentry->d_sb)->mount_crypt_stat;
+	size_t written;
+	struct ecryptfs_key_record key_rec;
+
+	(*len) = 0;
+	if (mount_crypt_stat->global_auth_tok) {
+		auth_tok = mount_crypt_stat->global_auth_tok;
+		if (auth_tok->token_type == ECRYPTFS_PASSWORD) {
+			rc = write_tag_3_packet((dest_base + (*len)),
+						max, auth_tok,
+						crypt_stat, &key_rec,
+						&written);
+			if (rc) {
+				ecryptfs_printk(KERN_WARNING, "Error "
+						"writing tag 3 packet\n");
+				goto out;
+			}
+			(*len) += written;
+			/* Write auth tok signature packet */
+			rc = write_tag_11_packet(
+				(dest_base + (*len)),
+				(max - (*len)),
+				key_rec.sig, ECRYPTFS_SIG_SIZE, &written);
+			if (rc) {
+				ecryptfs_printk(KERN_ERR, "Error writing "
+						"auth tok signature packet\n");
+				goto out;
+			}
+			(*len) += written;
+		} else {
+			ecryptfs_printk(KERN_WARNING, "Unsupported "
+					"authentication token type\n");
+			rc = -EINVAL;
+			goto out;
+		}
+		if (rc) {
+			ecryptfs_printk(KERN_WARNING, "Error writing "
+					"authentication token packet with sig "
+					"= [%s]\n",
+					mount_crypt_stat->global_auth_tok_sig);
+			rc = -EIO;
+			goto out;
+		}
+	} else
+		BUG();
+	if (likely((max - (*len)) > 0)) {
+		dest_base[(*len)] = 0x00;
+	} else {
+		ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n");
+		rc = -EIO;
+	}
+out:
+	if (rc)
+		(*len) = 0;
+	return rc;
+}
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
new file mode 100644
index 0000000..7a11b8a
--- /dev/null
+++ b/fs/ecryptfs/main.c
@@ -0,0 +1,831 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *              Michael C. Thompson <mcthomps@us.ibm.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 <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/skbuff.h>
+#include <linux/crypto.h>
+#include <linux/netlink.h>
+#include <linux/mount.h>
+#include <linux/dcache.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/parser.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * Module parameter that defines the ecryptfs_verbosity level.
+ */
+int ecryptfs_verbosity = 0;
+
+module_param(ecryptfs_verbosity, int, 0);
+MODULE_PARM_DESC(ecryptfs_verbosity,
+		 "Initial verbosity level (0 or 1; defaults to "
+		 "0, which is Quiet)");
+
+void __ecryptfs_printk(const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	if (fmt[1] == '7') { /* KERN_DEBUG */
+		if (ecryptfs_verbosity >= 1)
+			vprintk(fmt, args);
+	} else
+		vprintk(fmt, args);
+	va_end(args);
+}
+
+/**
+ * ecryptfs_interpose
+ * @lower_dentry: Existing dentry in the lower filesystem
+ * @dentry: ecryptfs' dentry
+ * @sb: ecryptfs's super_block
+ * @flag: If set to true, then d_add is called, else d_instantiate is called
+ *
+ * Interposes upper and lower dentries.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
+		       struct super_block *sb, int flag)
+{
+	struct inode *lower_inode;
+	struct inode *inode;
+	int rc = 0;
+
+	lower_inode = lower_dentry->d_inode;
+	if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
+		rc = -EXDEV;
+		goto out;
+	}
+	if (!igrab(lower_inode)) {
+		rc = -ESTALE;
+		goto out;
+	}
+	inode = iget5_locked(sb, (unsigned long)lower_inode,
+			     ecryptfs_inode_test, ecryptfs_inode_set,
+			     lower_inode);
+	if (!inode) {
+		rc = -EACCES;
+		iput(lower_inode);
+		goto out;
+	}
+	if (inode->i_state & I_NEW)
+		unlock_new_inode(inode);
+	else
+		iput(lower_inode);
+	if (S_ISLNK(lower_inode->i_mode))
+		inode->i_op = &ecryptfs_symlink_iops;
+	else if (S_ISDIR(lower_inode->i_mode))
+		inode->i_op = &ecryptfs_dir_iops;
+	if (S_ISDIR(lower_inode->i_mode))
+		inode->i_fop = &ecryptfs_dir_fops;
+	/* TODO: Is there a better way to identify if the inode is
+	 * special? */
+	if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) ||
+	    S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode))
+		init_special_inode(inode, lower_inode->i_mode,
+				   lower_inode->i_rdev);
+	dentry->d_op = &ecryptfs_dops;
+	if (flag)
+		d_add(dentry, inode);
+	else
+		d_instantiate(dentry, inode);
+	ecryptfs_copy_attr_all(inode, lower_inode);
+	/* This size will be overwritten for real files w/ headers and
+	 * other metadata */
+	ecryptfs_copy_inode_size(inode, lower_inode);
+out:
+	return rc;
+}
+
+enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
+       ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
+       ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
+       ecryptfs_opt_passthrough, ecryptfs_opt_err };
+
+static match_table_t tokens = {
+	{ecryptfs_opt_sig, "sig=%s"},
+	{ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
+	{ecryptfs_opt_debug, "debug=%u"},
+	{ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
+	{ecryptfs_opt_cipher, "cipher=%s"},
+	{ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
+	{ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
+	{ecryptfs_opt_passthrough, "ecryptfs_passthrough"},
+	{ecryptfs_opt_err, NULL}
+};
+
+/**
+ * ecryptfs_verify_version
+ * @version: The version number to confirm
+ *
+ * Returns zero on good version; non-zero otherwise
+ */
+static int ecryptfs_verify_version(u16 version)
+{
+	int rc = 0;
+	unsigned char major;
+	unsigned char minor;
+
+	major = ((version >> 8) & 0xFF);
+	minor = (version & 0xFF);
+	if (major != ECRYPTFS_VERSION_MAJOR) {
+		ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
+				"Expected [%d]; got [%d]\n",
+				ECRYPTFS_VERSION_MAJOR, major);
+		rc = -EINVAL;
+		goto out;
+	}
+	if (minor != ECRYPTFS_VERSION_MINOR) {
+		ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
+				"Expected [%d]; got [%d]\n",
+				ECRYPTFS_VERSION_MINOR, minor);
+		rc = -EINVAL;
+		goto out;
+	}
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_parse_options
+ * @sb: The ecryptfs super block
+ * @options: The options pased to the kernel
+ *
+ * Parse mount options:
+ * debug=N 	   - ecryptfs_verbosity level for debug output
+ * sig=XXX	   - description(signature) of the key to use
+ *
+ * Returns the dentry object of the lower-level (lower/interposed)
+ * directory; We want to mount our stackable file system on top of
+ * that lower directory.
+ *
+ * The signature of the key to use must be the description of a key
+ * already in the keyring. Mounting will fail if the key can not be
+ * found.
+ *
+ * Returns zero on success; non-zero on error
+ */
+static int ecryptfs_parse_options(struct super_block *sb, char *options)
+{
+	char *p;
+	int rc = 0;
+	int sig_set = 0;
+	int cipher_name_set = 0;
+	int cipher_key_bytes;
+	int cipher_key_bytes_set = 0;
+	struct key *auth_tok_key = NULL;
+	struct ecryptfs_auth_tok *auth_tok = NULL;
+	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+		&ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
+	substring_t args[MAX_OPT_ARGS];
+	int token;
+	char *sig_src;
+	char *sig_dst;
+	char *debug_src;
+	char *cipher_name_dst;
+	char *cipher_name_src;
+	char *cipher_key_bytes_src;
+	struct crypto_tfm *tmp_tfm;
+	int cipher_name_len;
+
+	if (!options) {
+		rc = -EINVAL;
+		goto out;
+	}
+	while ((p = strsep(&options, ",")) != NULL) {
+		if (!*p)
+			continue;
+		token = match_token(p, tokens, args);
+		switch (token) {
+		case ecryptfs_opt_sig:
+		case ecryptfs_opt_ecryptfs_sig:
+			sig_src = args[0].from;
+			sig_dst =
+				mount_crypt_stat->global_auth_tok_sig;
+			memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX);
+			sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+			ecryptfs_printk(KERN_DEBUG,
+					"The mount_crypt_stat "
+					"global_auth_tok_sig set to: "
+					"[%s]\n", sig_dst);
+			sig_set = 1;
+			break;
+		case ecryptfs_opt_debug:
+		case ecryptfs_opt_ecryptfs_debug:
+			debug_src = args[0].from;
+			ecryptfs_verbosity =
+				(int)simple_strtol(debug_src, &debug_src,
+						   0);
+			ecryptfs_printk(KERN_DEBUG,
+					"Verbosity set to [%d]" "\n",
+					ecryptfs_verbosity);
+			break;
+		case ecryptfs_opt_cipher:
+		case ecryptfs_opt_ecryptfs_cipher:
+			cipher_name_src = args[0].from;
+			cipher_name_dst =
+				mount_crypt_stat->
+				global_default_cipher_name;
+			strncpy(cipher_name_dst, cipher_name_src,
+				ECRYPTFS_MAX_CIPHER_NAME_SIZE);
+			ecryptfs_printk(KERN_DEBUG,
+					"The mount_crypt_stat "
+					"global_default_cipher_name set to: "
+					"[%s]\n", cipher_name_dst);
+			cipher_name_set = 1;
+			break;
+		case ecryptfs_opt_ecryptfs_key_bytes:
+			cipher_key_bytes_src = args[0].from;
+			cipher_key_bytes =
+				(int)simple_strtol(cipher_key_bytes_src,
+						   &cipher_key_bytes_src, 0);
+			mount_crypt_stat->global_default_cipher_key_size =
+				cipher_key_bytes;
+			ecryptfs_printk(KERN_DEBUG,
+					"The mount_crypt_stat "
+					"global_default_cipher_key_size "
+					"set to: [%d]\n", mount_crypt_stat->
+					global_default_cipher_key_size);
+			cipher_key_bytes_set = 1;
+			break;
+		case ecryptfs_opt_passthrough:
+			mount_crypt_stat->flags |=
+				ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED;
+			break;
+		case ecryptfs_opt_err:
+		default:
+			ecryptfs_printk(KERN_WARNING,
+					"eCryptfs: unrecognized option '%s'\n",
+					p);
+		}
+	}
+	/* Do not support lack of mount-wide signature in 0.1
+	 * release */
+	if (!sig_set) {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_ERR, "You must supply a valid "
+				"passphrase auth tok signature as a mount "
+				"parameter; see the eCryptfs README\n");
+		goto out;
+	}
+	if (!cipher_name_set) {
+		cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
+		if (unlikely(cipher_name_len
+			     >= ECRYPTFS_MAX_CIPHER_NAME_SIZE)) {
+			rc = -EINVAL;
+			BUG();
+			goto out;
+		}
+		memcpy(mount_crypt_stat->global_default_cipher_name,
+		       ECRYPTFS_DEFAULT_CIPHER, cipher_name_len);
+		mount_crypt_stat->global_default_cipher_name[cipher_name_len]
+		    = '\0';
+	}
+	if (!cipher_key_bytes_set) {
+		mount_crypt_stat->global_default_cipher_key_size =
+			ECRYPTFS_DEFAULT_KEY_BYTES;
+		ecryptfs_printk(KERN_DEBUG, "Cipher key size was not "
+				"specified.  Defaulting to [%d]\n",
+				mount_crypt_stat->
+				global_default_cipher_key_size);
+	}
+	rc = ecryptfs_process_cipher(
+		&tmp_tfm,
+		&mount_crypt_stat->global_key_tfm,
+		mount_crypt_stat->global_default_cipher_name,
+		mount_crypt_stat->global_default_cipher_key_size);
+	if (tmp_tfm)
+		crypto_free_tfm(tmp_tfm);
+	if (rc) {
+		printk(KERN_ERR "Error attempting to initialize cipher [%s] "
+		       "with key size [%Zd] bytes; rc = [%d]\n",
+		       mount_crypt_stat->global_default_cipher_name,
+		       mount_crypt_stat->global_default_cipher_key_size, rc);
+		rc = -EINVAL;
+		goto out;
+	}
+	mutex_init(&mount_crypt_stat->global_key_tfm_mutex);
+	ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: "
+			"[%s]\n", mount_crypt_stat->global_auth_tok_sig);
+	/* The reference to this key is held until umount is done The
+	 * call to key_put is done in ecryptfs_put_super() */
+	auth_tok_key = request_key(&key_type_user,
+				   mount_crypt_stat->global_auth_tok_sig,
+				   NULL);
+	if (!auth_tok_key || IS_ERR(auth_tok_key)) {
+		ecryptfs_printk(KERN_ERR, "Could not find key with "
+				"description: [%s]\n",
+				mount_crypt_stat->global_auth_tok_sig);
+		process_request_key_err(PTR_ERR(auth_tok_key));
+		rc = -EINVAL;
+		goto out;
+	}
+	auth_tok = ecryptfs_get_key_payload_data(auth_tok_key);
+	if (ecryptfs_verify_version(auth_tok->version)) {
+		ecryptfs_printk(KERN_ERR, "Data structure version mismatch. "
+				"Userspace tools must match eCryptfs kernel "
+				"module with major version [%d] and minor "
+				"version [%d]\n", ECRYPTFS_VERSION_MAJOR,
+				ECRYPTFS_VERSION_MINOR);
+		rc = -EINVAL;
+		goto out;
+	}
+	if (auth_tok->token_type != ECRYPTFS_PASSWORD) {
+		ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure "
+				"returned from key\n");
+		rc = -EINVAL;
+		goto out;
+	}
+	mount_crypt_stat->global_auth_tok_key = auth_tok_key;
+	mount_crypt_stat->global_auth_tok = auth_tok;
+out:
+	return rc;
+}
+
+struct kmem_cache *ecryptfs_sb_info_cache;
+
+/**
+ * ecryptfs_fill_super
+ * @sb: The ecryptfs super block
+ * @raw_data: The options passed to mount
+ * @silent: Not used but required by function prototype
+ *
+ * Sets up what we can of the sb, rest is done in ecryptfs_read_super
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)
+{
+	int rc = 0;
+
+	/* Released in ecryptfs_put_super() */
+	ecryptfs_set_superblock_private(sb,
+					kmem_cache_alloc(ecryptfs_sb_info_cache,
+							 SLAB_KERNEL));
+	if (!ecryptfs_superblock_to_private(sb)) {
+		ecryptfs_printk(KERN_WARNING, "Out of memory\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(ecryptfs_superblock_to_private(sb), 0,
+	       sizeof(struct ecryptfs_sb_info));
+	sb->s_op = &ecryptfs_sops;
+	/* Released through deactivate_super(sb) from get_sb_nodev */
+	sb->s_root = d_alloc(NULL, &(const struct qstr) {
+			     .hash = 0,.name = "/",.len = 1});
+	if (!sb->s_root) {
+		ecryptfs_printk(KERN_ERR, "d_alloc failed\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	sb->s_root->d_op = &ecryptfs_dops;
+	sb->s_root->d_sb = sb;
+	sb->s_root->d_parent = sb->s_root;
+	/* Released in d_release when dput(sb->s_root) is called */
+	/* through deactivate_super(sb) from get_sb_nodev() */
+	ecryptfs_set_dentry_private(sb->s_root,
+				    kmem_cache_alloc(ecryptfs_dentry_info_cache,
+						     SLAB_KERNEL));
+	if (!ecryptfs_dentry_to_private(sb->s_root)) {
+		ecryptfs_printk(KERN_ERR,
+				"dentry_info_cache alloc failed\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset(ecryptfs_dentry_to_private(sb->s_root), 0,
+	       sizeof(struct ecryptfs_dentry_info));
+	rc = 0;
+out:
+	/* Should be able to rely on deactivate_super called from
+	 * get_sb_nodev */
+	return rc;
+}
+
+/**
+ * ecryptfs_read_super
+ * @sb: The ecryptfs super block
+ * @dev_name: The path to mount over
+ *
+ * Read the super block of the lower filesystem, and use
+ * ecryptfs_interpose to create our initial inode and super block
+ * struct.
+ */
+static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
+{
+	int rc;
+	struct nameidata nd;
+	struct dentry *lower_root;
+	struct vfsmount *lower_mnt;
+
+	memset(&nd, 0, sizeof(struct nameidata));
+	rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
+		goto out_free;
+	}
+	lower_root = nd.dentry;
+	if (!lower_root->d_inode) {
+		ecryptfs_printk(KERN_WARNING,
+				"No directory to interpose on\n");
+		rc = -ENOENT;
+		goto out_free;
+	}
+	lower_mnt = nd.mnt;
+	ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
+	sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
+	ecryptfs_set_dentry_lower(sb->s_root, lower_root);
+	ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
+	if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
+		goto out_free;
+	rc = 0;
+	goto out;
+out_free:
+	path_release(&nd);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_get_sb
+ * @fs_type
+ * @flags
+ * @dev_name: The path to mount over
+ * @raw_data: The options passed into the kernel
+ *
+ * The whole ecryptfs_get_sb process is broken into 4 functions:
+ * ecryptfs_parse_options(): handle options passed to ecryptfs, if any
+ * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block
+ *                        with as much information as it can before needing
+ *                        the lower filesystem.
+ * ecryptfs_read_super(): this accesses the lower filesystem and uses
+ *                        ecryptfs_interpolate to perform most of the linking
+ * ecryptfs_interpolate(): links the lower filesystem into ecryptfs
+ */
+static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
+			const char *dev_name, void *raw_data,
+			struct vfsmount *mnt)
+{
+	int rc;
+	struct super_block *sb;
+
+	rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt);
+	if (rc < 0) {
+		printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc);
+		goto out;
+	}
+	sb = mnt->mnt_sb;
+	rc = ecryptfs_parse_options(sb, raw_data);
+	if (rc) {
+		printk(KERN_ERR "Error parsing options; rc = [%d]\n", rc);
+		goto out_abort;
+	}
+	rc = ecryptfs_read_super(sb, dev_name);
+	if (rc) {
+		printk(KERN_ERR "Reading sb failed; rc = [%d]\n", rc);
+		goto out_abort;
+	}
+	goto out;
+out_abort:
+	dput(sb->s_root);
+	up_write(&sb->s_umount);
+	deactivate_super(sb);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_kill_block_super
+ * @sb: The ecryptfs super block
+ *
+ * Used to bring the superblock down and free the private data.
+ * Private data is free'd in ecryptfs_put_super()
+ */
+static void ecryptfs_kill_block_super(struct super_block *sb)
+{
+	generic_shutdown_super(sb);
+}
+
+static struct file_system_type ecryptfs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "ecryptfs",
+	.get_sb = ecryptfs_get_sb,
+	.kill_sb = ecryptfs_kill_block_super,
+	.fs_flags = 0
+};
+
+/**
+ * inode_info_init_once
+ *
+ * Initializes the ecryptfs_inode_info_cache when it is created
+ */
+static void
+inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags)
+{
+	struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
+
+	if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR)
+		inode_init_once(&ei->vfs_inode);
+}
+
+static struct ecryptfs_cache_info {
+	kmem_cache_t **cache;
+	const char *name;
+	size_t size;
+	void (*ctor)(void*, struct kmem_cache *, unsigned long);
+} ecryptfs_cache_infos[] = {
+	{
+		.cache = &ecryptfs_auth_tok_list_item_cache,
+		.name = "ecryptfs_auth_tok_list_item",
+		.size = sizeof(struct ecryptfs_auth_tok_list_item),
+	},
+	{
+		.cache = &ecryptfs_file_info_cache,
+		.name = "ecryptfs_file_cache",
+		.size = sizeof(struct ecryptfs_file_info),
+	},
+	{
+		.cache = &ecryptfs_dentry_info_cache,
+		.name = "ecryptfs_dentry_info_cache",
+		.size = sizeof(struct ecryptfs_dentry_info),
+	},
+	{
+		.cache = &ecryptfs_inode_info_cache,
+		.name = "ecryptfs_inode_cache",
+		.size = sizeof(struct ecryptfs_inode_info),
+		.ctor = inode_info_init_once,
+	},
+	{
+		.cache = &ecryptfs_sb_info_cache,
+		.name = "ecryptfs_sb_cache",
+		.size = sizeof(struct ecryptfs_sb_info),
+	},
+	{
+		.cache = &ecryptfs_header_cache_0,
+		.name = "ecryptfs_headers_0",
+		.size = PAGE_CACHE_SIZE,
+	},
+	{
+		.cache = &ecryptfs_header_cache_1,
+		.name = "ecryptfs_headers_1",
+		.size = PAGE_CACHE_SIZE,
+	},
+	{
+		.cache = &ecryptfs_header_cache_2,
+		.name = "ecryptfs_headers_2",
+		.size = PAGE_CACHE_SIZE,
+	},
+	{
+		.cache = &ecryptfs_lower_page_cache,
+		.name = "ecryptfs_lower_page_cache",
+		.size = PAGE_CACHE_SIZE,
+	},
+};
+
+static void ecryptfs_free_kmem_caches(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
+		struct ecryptfs_cache_info *info;
+
+		info = &ecryptfs_cache_infos[i];
+		if (*(info->cache))
+			kmem_cache_destroy(*(info->cache));
+	}
+}
+
+/**
+ * ecryptfs_init_kmem_caches
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_init_kmem_caches(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
+		struct ecryptfs_cache_info *info;
+
+		info = &ecryptfs_cache_infos[i];
+		*(info->cache) = kmem_cache_create(info->name, info->size,
+				0, SLAB_HWCACHE_ALIGN, info->ctor, NULL);
+		if (!*(info->cache)) {
+			ecryptfs_free_kmem_caches();
+			ecryptfs_printk(KERN_WARNING, "%s: "
+					"kmem_cache_create failed\n",
+					info->name);
+			return -ENOMEM;
+		}
+	}
+	return 0;
+}
+
+struct ecryptfs_obj {
+	char *name;
+	struct list_head slot_list;
+	struct kobject kobj;
+};
+
+struct ecryptfs_attribute {
+	struct attribute attr;
+	ssize_t(*show) (struct ecryptfs_obj *, char *);
+	ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
+};
+
+static ssize_t
+ecryptfs_attr_store(struct kobject *kobj,
+		    struct attribute *attr, const char *buf, size_t len)
+{
+	struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+						kobj);
+	struct ecryptfs_attribute *attribute =
+		container_of(attr, struct ecryptfs_attribute, attr);
+
+	return (attribute->store ? attribute->store(obj, buf, len) : 0);
+}
+
+static ssize_t
+ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+						kobj);
+	struct ecryptfs_attribute *attribute =
+		container_of(attr, struct ecryptfs_attribute, attr);
+
+	return (attribute->show ? attribute->show(obj, buf) : 0);
+}
+
+static struct sysfs_ops ecryptfs_sysfs_ops = {
+	.show = ecryptfs_attr_show,
+	.store = ecryptfs_attr_store
+};
+
+static struct kobj_type ecryptfs_ktype = {
+	.sysfs_ops = &ecryptfs_sysfs_ops
+};
+
+static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
+
+static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
+{
+	return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
+}
+
+static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
+
+struct ecryptfs_version_str_map_elem {
+	u32 flag;
+	char *str;
+} ecryptfs_version_str_map[] = {
+	{ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
+	{ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
+	{ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
+	{ECRYPTFS_VERSIONING_POLICY, "policy"}
+};
+
+static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
+{
+	int i;
+	int remaining = PAGE_SIZE;
+	int total_written = 0;
+
+	buff[0] = '\0';
+	for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
+		int entry_size;
+
+		if (!(ECRYPTFS_VERSIONING_MASK
+		      & ecryptfs_version_str_map[i].flag))
+			continue;
+		entry_size = strlen(ecryptfs_version_str_map[i].str);
+		if ((entry_size + 2) > remaining)
+			goto out;
+		memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
+		buff[entry_size++] = '\n';
+		buff[entry_size] = '\0';
+		buff += entry_size;
+		total_written += entry_size;
+		remaining -= entry_size;
+	}
+out:
+	return total_written;
+}
+
+static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
+
+static int do_sysfs_registration(void)
+{
+	int rc;
+
+	if ((rc = subsystem_register(&ecryptfs_subsys))) {
+		printk(KERN_ERR
+		       "Unable to register ecryptfs sysfs subsystem\n");
+		goto out;
+	}
+	rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+			       &sysfs_attr_version.attr);
+	if (rc) {
+		printk(KERN_ERR
+		       "Unable to create ecryptfs version attribute\n");
+		subsystem_unregister(&ecryptfs_subsys);
+		goto out;
+	}
+	rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+			       &sysfs_attr_version_str.attr);
+	if (rc) {
+		printk(KERN_ERR
+		       "Unable to create ecryptfs version_str attribute\n");
+		sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+				  &sysfs_attr_version.attr);
+		subsystem_unregister(&ecryptfs_subsys);
+		goto out;
+	}
+out:
+	return rc;
+}
+
+static int __init ecryptfs_init(void)
+{
+	int rc;
+
+	if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_CACHE_SIZE) {
+		rc = -EINVAL;
+		ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is "
+				"larger than the host's page size, and so "
+				"eCryptfs cannot run on this system. The "
+				"default eCryptfs extent size is [%d] bytes; "
+				"the page size is [%d] bytes.\n",
+				ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE);
+		goto out;
+	}
+	rc = ecryptfs_init_kmem_caches();
+	if (rc) {
+		printk(KERN_ERR
+		       "Failed to allocate one or more kmem_cache objects\n");
+		goto out;
+	}
+	rc = register_filesystem(&ecryptfs_fs_type);
+	if (rc) {
+		printk(KERN_ERR "Failed to register filesystem\n");
+		ecryptfs_free_kmem_caches();
+		goto out;
+	}
+	kset_set_kset_s(&ecryptfs_subsys, fs_subsys);
+	sysfs_attr_version.attr.owner = THIS_MODULE;
+	sysfs_attr_version_str.attr.owner = THIS_MODULE;
+	rc = do_sysfs_registration();
+	if (rc) {
+		printk(KERN_ERR "sysfs registration failed\n");
+		unregister_filesystem(&ecryptfs_fs_type);
+		ecryptfs_free_kmem_caches();
+		goto out;
+	}
+out:
+	return rc;
+}
+
+static void __exit ecryptfs_exit(void)
+{
+	sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+			  &sysfs_attr_version.attr);
+	sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+			  &sysfs_attr_version_str.attr);
+	subsystem_unregister(&ecryptfs_subsys);
+	unregister_filesystem(&ecryptfs_fs_type);
+	ecryptfs_free_kmem_caches();
+}
+
+MODULE_AUTHOR("Michael A. Halcrow <mhalcrow@us.ibm.com>");
+MODULE_DESCRIPTION("eCryptfs");
+
+MODULE_LICENSE("GPL");
+
+module_init(ecryptfs_init)
+module_exit(ecryptfs_exit)
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
new file mode 100644
index 0000000..924dd90
--- /dev/null
+++ b/fs/ecryptfs/mmap.c
@@ -0,0 +1,788 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * This is where eCryptfs coordinates the symmetric encryption and
+ * decryption of the file data as it passes between the lower
+ * encrypted file and the upper decrypted file.
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.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 <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/page-flags.h>
+#include <linux/mount.h>
+#include <linux/file.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+struct kmem_cache *ecryptfs_lower_page_cache;
+
+/**
+ * ecryptfs_get1page
+ *
+ * Get one page from cache or lower f/s, return error otherwise.
+ *
+ * Returns unlocked and up-to-date page (if ok), with increased
+ * refcnt.
+ */
+static struct page *ecryptfs_get1page(struct file *file, int index)
+{
+	struct page *page;
+	struct dentry *dentry;
+	struct inode *inode;
+	struct address_space *mapping;
+
+	dentry = file->f_dentry;
+	inode = dentry->d_inode;
+	mapping = inode->i_mapping;
+	page = read_cache_page(mapping, index,
+			       (filler_t *)mapping->a_ops->readpage,
+			       (void *)file);
+	if (IS_ERR(page))
+		goto out;
+	wait_on_page_locked(page);
+out:
+	return page;
+}
+
+static
+int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
+
+/**
+ * ecryptfs_fill_zeros
+ * @file: The ecryptfs file
+ * @new_length: The new length of the data in the underlying file;
+ *              everything between the prior end of the file and the
+ *              new end of the file will be filled with zero's.
+ *              new_length must be greater than  current length
+ *
+ * Function for handling lseek-ing past the end of the file.
+ *
+ * This function does not support shrinking, only growing a file.
+ *
+ * Returns zero on success; non-zero otherwise.
+ */
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
+{
+	int rc = 0;
+	struct dentry *dentry = file->f_dentry;
+	struct inode *inode = dentry->d_inode;
+	pgoff_t old_end_page_index = 0;
+	pgoff_t index = old_end_page_index;
+	int old_end_pos_in_page = -1;
+	pgoff_t new_end_page_index;
+	int new_end_pos_in_page;
+	loff_t cur_length = i_size_read(inode);
+
+	if (cur_length != 0) {
+		index = old_end_page_index =
+		    ((cur_length - 1) >> PAGE_CACHE_SHIFT);
+		old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK);
+	}
+	new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
+	new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
+	ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; "
+			"old_end_pos_in_page = [%d]; "
+			"new_end_page_index = [0x%.16x]; "
+			"new_end_pos_in_page = [%d]\n",
+			old_end_page_index, old_end_pos_in_page,
+			new_end_page_index, new_end_pos_in_page);
+	if (old_end_page_index == new_end_page_index) {
+		/* Start and end are in the same page; we just need to
+		 * set a portion of the existing page to zero's */
+		rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+				 (new_end_pos_in_page - old_end_pos_in_page));
+		if (rc)
+			ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+					"index=[0x%.16x], "
+					"old_end_pos_in_page=[d], "
+					"(PAGE_CACHE_SIZE - new_end_pos_in_page"
+					"=[%d]"
+					")=[d]) returned [%d]\n", file, index,
+					old_end_pos_in_page,
+					new_end_pos_in_page,
+					(PAGE_CACHE_SIZE - new_end_pos_in_page),
+					rc);
+		goto out;
+	}
+	/* Fill the remainder of the previous last page with zeros */
+	rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+			 ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+				"index=[0x%.16x], old_end_pos_in_page=[d], "
+				"(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
+				"returned [%d]\n", file, index,
+				old_end_pos_in_page,
+				(PAGE_CACHE_SIZE - old_end_pos_in_page), rc);
+		goto out;
+	}
+	index++;
+	while (index < new_end_page_index) {
+		/* Fill all intermediate pages with zeros */
+		rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+					"index=[0x%.16x], "
+					"old_end_pos_in_page=[d], "
+					"(PAGE_CACHE_SIZE - new_end_pos_in_page"
+					"=[%d]"
+					")=[d]) returned [%d]\n", file, index,
+					old_end_pos_in_page,
+					new_end_pos_in_page,
+					(PAGE_CACHE_SIZE - new_end_pos_in_page),
+					rc);
+			goto out;
+		}
+		index++;
+	}
+	/* Fill the portion at the beginning of the last new page with
+	 * zero's */
+	rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1));
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "write_zeros(file="
+				"[%p], index=[0x%.16x], 0, "
+				"new_end_pos_in_page=[%d]"
+				"returned [%d]\n", file, index,
+				new_end_pos_in_page, rc);
+		goto out;
+	}
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_writepage
+ * @page: Page that is locked before this call is made
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+	struct ecryptfs_page_crypt_context ctx;
+	int rc;
+
+	ctx.page = page;
+	ctx.mode = ECRYPTFS_WRITEPAGE_MODE;
+	ctx.param.wbc = wbc;
+	rc = ecryptfs_encrypt_page(&ctx);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "Error encrypting "
+				"page (upper index [0x%.16x])\n", page->index);
+		ClearPageUptodate(page);
+		goto out;
+	}
+	SetPageUptodate(page);
+	unlock_page(page);
+out:
+	return rc;
+}
+
+/**
+ * Reads the data from the lower file file at index lower_page_index
+ * and copies that data into page.
+ *
+ * @param page	Page to fill
+ * @param lower_page_index Index of the page in the lower file to get
+ */
+int ecryptfs_do_readpage(struct file *file, struct page *page,
+			 pgoff_t lower_page_index)
+{
+	int rc;
+	struct dentry *dentry;
+	struct file *lower_file;
+	struct dentry *lower_dentry;
+	struct inode *inode;
+	struct inode *lower_inode;
+	char *page_data;
+	struct page *lower_page = NULL;
+	char *lower_page_data;
+	const struct address_space_operations *lower_a_ops;
+
+	dentry = file->f_dentry;
+	lower_file = ecryptfs_file_to_lower(file);
+	lower_dentry = ecryptfs_dentry_to_lower(dentry);
+	inode = dentry->d_inode;
+	lower_inode = ecryptfs_inode_to_lower(inode);
+	lower_a_ops = lower_inode->i_mapping->a_ops;
+	lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index,
+				     (filler_t *)lower_a_ops->readpage,
+				     (void *)lower_file);
+	if (IS_ERR(lower_page)) {
+		rc = PTR_ERR(lower_page);
+		lower_page = NULL;
+		ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
+		goto out;
+	}
+	wait_on_page_locked(lower_page);
+	page_data = (char *)kmap(page);
+	if (!page_data) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR, "Error mapping page\n");
+		goto out;
+	}
+	lower_page_data = (char *)kmap(lower_page);
+	if (!lower_page_data) {
+		rc = -ENOMEM;
+		ecryptfs_printk(KERN_ERR, "Error mapping page\n");
+		kunmap(page);
+		goto out;
+	}
+	memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
+	kunmap(lower_page);
+	kunmap(page);
+	rc = 0;
+out:
+	if (likely(lower_page))
+		page_cache_release(lower_page);
+	if (rc == 0)
+		SetPageUptodate(page);
+	else
+		ClearPageUptodate(page);
+	return rc;
+}
+
+/**
+ * ecryptfs_readpage
+ * @file: This is an ecryptfs file
+ * @page: ecryptfs associated page to stick the read data into
+ *
+ * Read in a page, decrypting if necessary.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int ecryptfs_readpage(struct file *file, struct page *page)
+{
+	int rc = 0;
+	struct ecryptfs_crypt_stat *crypt_stat;
+
+	BUG_ON(!(file && file->f_dentry && file->f_dentry->d_inode));
+	crypt_stat =
+		&ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+	if (!crypt_stat
+	    || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)
+	    || ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
+		ecryptfs_printk(KERN_DEBUG,
+				"Passing through unencrypted page\n");
+		rc = ecryptfs_do_readpage(file, page, page->index);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error reading page; rc = "
+					"[%d]\n", rc);
+			goto out;
+		}
+	} else {
+		rc = ecryptfs_decrypt_page(file, page);
+		if (rc) {
+
+			ecryptfs_printk(KERN_ERR, "Error decrypting page; "
+					"rc = [%d]\n", rc);
+			goto out;
+		}
+	}
+	SetPageUptodate(page);
+out:
+	if (rc)
+		ClearPageUptodate(page);
+	ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
+			page->index);
+	unlock_page(page);
+	return rc;
+}
+
+static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
+{
+	struct inode *inode = page->mapping->host;
+	int end_byte_in_page;
+	int rc = 0;
+	char *page_virt;
+
+	if ((i_size_read(inode) / PAGE_CACHE_SIZE) == page->index) {
+		end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
+		if (to > end_byte_in_page)
+			end_byte_in_page = to;
+		page_virt = kmap(page);
+		if (!page_virt) {
+			rc = -ENOMEM;
+			ecryptfs_printk(KERN_WARNING,
+					"Could not map page\n");
+			goto out;
+		}
+		memset((page_virt + end_byte_in_page), 0,
+		       (PAGE_CACHE_SIZE - end_byte_in_page));
+		kunmap(page);
+	}
+out:
+	return rc;
+}
+
+static int ecryptfs_prepare_write(struct file *file, struct page *page,
+				  unsigned from, unsigned to)
+{
+	int rc = 0;
+
+	kmap(page);
+	if (from == 0 && to == PAGE_CACHE_SIZE)
+		goto out;	/* If we are writing a full page, it will be
+				   up to date. */
+	if (!PageUptodate(page))
+		rc = ecryptfs_do_readpage(file, page, page->index);
+out:
+	return rc;
+}
+
+int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
+				     char **lower_virt,
+				     struct inode *lower_inode,
+				     unsigned long lower_page_index)
+{
+	int rc = 0;
+
+	(*lower_page) = grab_cache_page(lower_inode->i_mapping,
+					lower_page_index);
+	if (!(*lower_page)) {
+		ecryptfs_printk(KERN_ERR, "grab_cache_page for "
+				"lower_page_index = [0x%.16x] failed\n",
+				lower_page_index);
+		rc = -EINVAL;
+		goto out;
+	}
+	if (lower_virt)
+		(*lower_virt) = kmap((*lower_page));
+	else
+		kmap((*lower_page));
+out:
+	return rc;
+}
+
+int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
+					      struct inode *lower_inode,
+					      struct writeback_control *wbc)
+{
+	int rc = 0;
+
+	rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); "
+				"rc = [%d]\n", rc);
+		goto out;
+	}
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+	page_cache_release(lower_page);
+out:
+	return rc;
+}
+
+static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page)
+{
+	kunmap(lower_page);
+	ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = "
+			"[0x%.16x]\n", lower_page->index);
+	unlock_page(lower_page);
+	page_cache_release(lower_page);
+}
+
+/**
+ * ecryptfs_write_inode_size_to_header
+ *
+ * Writes the lower file size to the first 8 bytes of the header.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+int
+ecryptfs_write_inode_size_to_header(struct file *lower_file,
+				    struct inode *lower_inode,
+				    struct inode *inode)
+{
+	int rc = 0;
+	struct page *header_page;
+	char *header_virt;
+	const struct address_space_operations *lower_a_ops;
+	u64 file_size;
+
+	rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt,
+					      lower_inode, 0);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "grab_cache_page for header page "
+				"failed\n");
+		goto out;
+	}
+	lower_a_ops = lower_inode->i_mapping->a_ops;
+	rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
+	file_size = (u64)i_size_read(inode);
+	ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
+	file_size = cpu_to_be64(file_size);
+	memcpy(header_virt, &file_size, sizeof(u64));
+	rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
+	if (rc < 0)
+		ecryptfs_printk(KERN_ERR, "Error commiting header page "
+				"write\n");
+	ecryptfs_unmap_and_release_lower_page(header_page);
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty_sync(inode);
+out:
+	return rc;
+}
+
+int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
+			    struct file *lower_file,
+			    unsigned long lower_page_index, int byte_offset,
+			    int region_bytes)
+{
+	int rc = 0;
+
+	rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, lower_inode,
+					      lower_page_index);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error attempting to grab and map "
+				"lower page with index [0x%.16x]\n",
+				lower_page_index);
+		goto out;
+	}
+	rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file,
+							  (*lower_page),
+							  byte_offset,
+							  region_bytes);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "prepare_write for "
+				"lower_page_index = [0x%.16x] failed; rc = "
+				"[%d]\n", lower_page_index, rc);
+	}
+out:
+	if (rc && (*lower_page)) {
+		ecryptfs_unmap_and_release_lower_page(*lower_page);
+		(*lower_page) = NULL;
+	}
+	return rc;
+}
+
+/**
+ * ecryptfs_commit_lower_page
+ *
+ * Returns zero on success; non-zero on error
+ */
+int
+ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
+			   struct file *lower_file, int byte_offset,
+			   int region_size)
+{
+	int rc = 0;
+
+	rc = lower_inode->i_mapping->a_ops->commit_write(
+		lower_file, lower_page, byte_offset, region_size);
+	if (rc < 0) {
+		ecryptfs_printk(KERN_ERR,
+				"Error committing write; rc = [%d]\n", rc);
+	} else
+		rc = 0;
+	ecryptfs_unmap_and_release_lower_page(lower_page);
+	return rc;
+}
+
+/**
+ * ecryptfs_copy_page_to_lower
+ *
+ * Used for plaintext pass-through; no page index interpolation
+ * required.
+ */
+int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
+				struct file *lower_file)
+{
+	int rc = 0;
+	struct page *lower_page;
+
+	rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file,
+				     page->index, 0, PAGE_CACHE_SIZE);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error attempting to get page "
+				"at index [0x%.16x]\n", page->index);
+		goto out;
+	}
+	/* TODO: aops */
+	memcpy((char *)page_address(lower_page), page_address(page),
+	       PAGE_CACHE_SIZE);
+	rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file,
+					0, PAGE_CACHE_SIZE);
+	if (rc)
+		ecryptfs_printk(KERN_ERR, "Error attempting to commit page "
+				"at index [0x%.16x]\n", page->index);
+out:
+	return rc;
+}
+
+static int
+process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
+		 struct file *file, struct inode *inode)
+{
+	struct page *header_page;
+	const struct address_space_operations *lower_a_ops;
+	struct inode *lower_inode;
+	struct file *lower_file;
+	char *header_virt;
+	int rc = 0;
+	int current_header_page = 0;
+	int header_pages;
+	int more_header_data_to_be_written = 1;
+
+	lower_inode = ecryptfs_inode_to_lower(inode);
+	lower_file = ecryptfs_file_to_lower(file);
+	lower_a_ops = lower_inode->i_mapping->a_ops;
+	header_pages = ((crypt_stat->header_extent_size
+			 * crypt_stat->num_header_extents_at_front)
+			/ PAGE_CACHE_SIZE);
+	BUG_ON(header_pages < 1);
+	while (current_header_page < header_pages) {
+		rc = ecryptfs_grab_and_map_lower_page(&header_page,
+						      &header_virt,
+						      lower_inode,
+						      current_header_page);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "grab_cache_page for "
+					"header page [%d] failed; rc = [%d]\n",
+					current_header_page, rc);
+			goto out;
+		}
+		rc = lower_a_ops->prepare_write(lower_file, header_page, 0,
+						PAGE_CACHE_SIZE);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error preparing to write "
+					"header page out; rc = [%d]\n", rc);
+			goto out;
+		}
+		memset(header_virt, 0, PAGE_CACHE_SIZE);
+		if (more_header_data_to_be_written) {
+			rc = ecryptfs_write_headers_virt(header_virt,
+							 crypt_stat,
+							 file->f_dentry);
+			if (rc) {
+				ecryptfs_printk(KERN_WARNING, "Error "
+						"generating header; rc = "
+						"[%d]\n", rc);
+				rc = -EIO;
+				memset(header_virt, 0, PAGE_CACHE_SIZE);
+				ecryptfs_unmap_and_release_lower_page(
+					header_page);
+				goto out;
+			}
+			if (current_header_page == 0)
+				memset(header_virt, 0, 8);
+			more_header_data_to_be_written = 0;
+		}
+		rc = lower_a_ops->commit_write(lower_file, header_page, 0,
+					       PAGE_CACHE_SIZE);
+		ecryptfs_unmap_and_release_lower_page(header_page);
+		if (rc < 0) {
+			ecryptfs_printk(KERN_ERR,
+					"Error commiting header page write; "
+					"rc = [%d]\n", rc);
+			break;
+		}
+		current_header_page++;
+	}
+	if (rc >= 0) {
+		rc = 0;
+		ecryptfs_printk(KERN_DEBUG, "lower_inode->i_blocks = "
+				"[0x%.16x]\n", lower_inode->i_blocks);
+		i_size_write(inode, 0);
+		lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty_sync(inode);
+	}
+	ecryptfs_printk(KERN_DEBUG, "Clearing ECRYPTFS_NEW_FILE flag in "
+			"crypt_stat at memory location [%p]\n", crypt_stat);
+	ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
+out:
+	return rc;
+}
+
+/**
+ * ecryptfs_commit_write
+ * @file: The eCryptfs file object
+ * @page: The eCryptfs page
+ * @from: Ignored (we rotate the page IV on each write)
+ * @to: Ignored
+ *
+ * This is where we encrypt the data and pass the encrypted data to
+ * the lower filesystem.  In OpenPGP-compatible mode, we operate on
+ * entire underlying packets.
+ */
+static int ecryptfs_commit_write(struct file *file, struct page *page,
+				 unsigned from, unsigned to)
+{
+	struct ecryptfs_page_crypt_context ctx;
+	loff_t pos;
+	struct inode *inode;
+	struct inode *lower_inode;
+	struct file *lower_file;
+	struct ecryptfs_crypt_stat *crypt_stat;
+	int rc;
+
+	inode = page->mapping->host;
+	lower_inode = ecryptfs_inode_to_lower(inode);
+	lower_file = ecryptfs_file_to_lower(file);
+	mutex_lock(&lower_inode->i_mutex);
+	crypt_stat =
+		&ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+	if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
+		ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
+			"crypt_stat at memory location [%p]\n", crypt_stat);
+		rc = process_new_file(crypt_stat, file, inode);
+		if (rc) {
+			ecryptfs_printk(KERN_ERR, "Error processing new "
+					"file; rc = [%d]\n", rc);
+			goto out;
+		}
+	} else
+		ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
+	ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
+			"(page w/ index = [0x%.16x], to = [%d])\n", page->index,
+			to);
+	rc = fill_zeros_to_end_of_page(page, to);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
+				"zeros in page with index = [0x%.16x]\n",
+				page->index);
+		goto out;
+	}
+	ctx.page = page;
+	ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE;
+	ctx.param.lower_file = lower_file;
+	rc = ecryptfs_encrypt_page(&ctx);
+	if (rc) {
+		ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
+				"index [0x%.16x])\n", page->index);
+		goto out;
+	}
+	rc = 0;
+	inode->i_blocks = lower_inode->i_blocks;
+	pos = (page->index << PAGE_CACHE_SHIFT) + to;
+	if (pos > i_size_read(inode)) {
+		i_size_write(inode, pos);
+		ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
+				"[0x%.16x]\n", i_size_read(inode));
+	}
+	ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+	lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+	mark_inode_dirty_sync(inode);
+out:
+	kunmap(page); /* mapped in prior call (prepare_write) */
+	if (rc < 0)
+		ClearPageUptodate(page);
+	else
+		SetPageUptodate(page);
+	mutex_unlock(&lower_inode->i_mutex);
+	return rc;
+}
+
+/**
+ * write_zeros
+ * @file: The ecryptfs file
+ * @index: The index in which we are writing
+ * @start: The position after the last block of data
+ * @num_zeros: The number of zeros to write
+ *
+ * Write a specified number of zero's to a page.
+ *
+ * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE
+ */
+static
+int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
+{
+	int rc = 0;
+	struct page *tmp_page;
+
+	tmp_page = ecryptfs_get1page(file, index);
+	if (IS_ERR(tmp_page)) {
+		ecryptfs_printk(KERN_ERR, "Error getting page at index "
+				"[0x%.16x]\n", index);
+		rc = PTR_ERR(tmp_page);
+		goto out;
+	}
+	kmap(tmp_page);
+	rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
+	if (rc) {
+		ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
+				"to remainder of page at index [0x%.16x]\n",
+				index);
+		kunmap(tmp_page);
+		page_cache_release(tmp_page);
+		goto out;
+	}
+	memset(((char *)page_address(tmp_page) + start), 0, num_zeros);
+	rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
+	if (rc < 0) {
+		ecryptfs_printk(KERN_ERR, "Error attempting to write zero's "
+				"to remainder of page at index [0x%.16x]\n",
+				index);
+		kunmap(tmp_page);
+		page_cache_release(tmp_page);
+		goto out;
+	}
+	rc = 0;
+	kunmap(tmp_page);
+	page_cache_release(tmp_page);
+out:
+	return rc;
+}
+
+static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
+{
+	int rc = 0;
+	struct inode *inode;
+	struct inode *lower_inode;
+
+	inode = (struct inode *)mapping->host;
+	lower_inode = ecryptfs_inode_to_lower(inode);
+	if (lower_inode->i_mapping->a_ops->bmap)
+		rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,
+							 block);
+	return rc;
+}
+
+static void ecryptfs_sync_page(struct page *page)
+{
+	struct inode *inode;
+	struct inode *lower_inode;
+	struct page *lower_page;
+
+	inode = page->mapping->host;
+	lower_inode = ecryptfs_inode_to_lower(inode);
+	/* NOTE: Recently swapped with grab_cache_page(), since
+	 * sync_page() just makes sure that pending I/O gets done. */
+	lower_page = find_lock_page(lower_inode->i_mapping, page->index);
+	if (!lower_page) {
+		ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n");
+		return;
+	}
+	lower_page->mapping->a_ops->sync_page(lower_page);
+	ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
+			lower_page->index);
+	unlock_page(lower_page);
+	page_cache_release(lower_page);
+}
+
+struct address_space_operations ecryptfs_aops = {
+	.writepage = ecryptfs_writepage,
+	.readpage = ecryptfs_readpage,
+	.prepare_write = ecryptfs_prepare_write,
+	.commit_write = ecryptfs_commit_write,
+	.bmap = ecryptfs_bmap,
+	.sync_page = ecryptfs_sync_page,
+};
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
new file mode 100644
index 0000000..c337c04
--- /dev/null
+++ b/fs/ecryptfs/super.c
@@ -0,0 +1,198 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ *              Michael C. Thompson <mcthomps@us.ibm.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 <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/key.h>
+#include <linux/seq_file.h>
+#include <linux/crypto.h>
+#include "ecryptfs_kernel.h"
+
+struct kmem_cache *ecryptfs_inode_info_cache;
+
+/**
+ * ecryptfs_alloc_inode - allocate an ecryptfs inode
+ * @sb: Pointer to the ecryptfs super block
+ *
+ * Called to bring an inode into existence.
+ *
+ * Only handle allocation, setting up structures should be done in
+ * ecryptfs_read_inode. This is because the kernel, between now and
+ * then, will 0 out the private data pointer.
+ *
+ * Returns a pointer to a newly allocated inode, NULL otherwise
+ */
+static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
+{
+	struct ecryptfs_inode_info *ecryptfs_inode;
+	struct inode *inode = NULL;
+
+	ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache,
+					  SLAB_KERNEL);
+	if (unlikely(!ecryptfs_inode))
+		goto out;
+	ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat);
+	inode = &ecryptfs_inode->vfs_inode;
+out:
+	return inode;
+}
+
+/**
+ * ecryptfs_destroy_inode
+ * @inode: The ecryptfs inode
+ *
+ * This is used during the final destruction of the inode.
+ * All allocation of memory related to the inode, including allocated
+ * memory in the crypt_stat struct, will be released here.
+ * There should be no chance that this deallocation will be missed.
+ */
+static void ecryptfs_destroy_inode(struct inode *inode)
+{
+	struct ecryptfs_inode_info *inode_info;
+
+	inode_info = ecryptfs_inode_to_private(inode);
+	ecryptfs_destruct_crypt_stat(&inode_info->crypt_stat);
+	kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
+}
+
+/**
+ * ecryptfs_init_inode
+ * @inode: The ecryptfs inode
+ *
+ * Set up the ecryptfs inode.
+ */
+void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
+{
+	ecryptfs_set_inode_lower(inode, lower_inode);
+	inode->i_ino = lower_inode->i_ino;
+	inode->i_version++;
+	inode->i_op = &ecryptfs_main_iops;
+	inode->i_fop = &ecryptfs_main_fops;
+	inode->i_mapping->a_ops = &ecryptfs_aops;
+}
+
+/**
+ * ecryptfs_put_super
+ * @sb: Pointer to the ecryptfs super block
+ *
+ * Final actions when unmounting a file system.
+ * This will handle deallocation and release of our private data.
+ */
+static void ecryptfs_put_super(struct super_block *sb)
+{
+	struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
+
+	ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat);
+	kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
+	ecryptfs_set_superblock_private(sb, NULL);
+}
+
+/**
+ * ecryptfs_statfs
+ * @sb: The ecryptfs super block
+ * @buf: The struct kstatfs to fill in with stats
+ *
+ * Get the filesystem statistics. Currently, we let this pass right through
+ * to the lower filesystem and take no action ourselves.
+ */
+static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
+}
+
+/**
+ * ecryptfs_clear_inode
+ * @inode - The ecryptfs inode
+ *
+ * Called by iput() when the inode reference count reached zero
+ * and the inode is not hashed anywhere.  Used to clear anything
+ * that needs to be, before the inode is completely destroyed and put
+ * on the inode free list. We use this to drop out reference to the
+ * lower inode.
+ */
+static void ecryptfs_clear_inode(struct inode *inode)
+{
+	iput(ecryptfs_inode_to_lower(inode));
+}
+
+/**
+ * ecryptfs_umount_begin
+ *
+ * Called in do_umount().
+ */
+static void ecryptfs_umount_begin(struct vfsmount *vfsmnt, int flags)
+{
+	struct vfsmount *lower_mnt =
+		ecryptfs_dentry_to_lower_mnt(vfsmnt->mnt_sb->s_root);
+	struct super_block *lower_sb;
+
+	mntput(lower_mnt);
+	lower_sb = lower_mnt->mnt_sb;
+	if (lower_sb->s_op->umount_begin)
+		lower_sb->s_op->umount_begin(lower_mnt, flags);
+}
+
+/**
+ * ecryptfs_show_options
+ *
+ * Prints the directory we are currently mounted over.
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+	struct super_block *sb = mnt->mnt_sb;
+	struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
+	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
+	char *tmp_page;
+	char *path;
+	int rc = 0;
+
+	tmp_page = (char *)__get_free_page(GFP_KERNEL);
+	if (!tmp_page) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
+	if (IS_ERR(path)) {
+		rc = PTR_ERR(path);
+		goto out;
+	}
+	seq_printf(m, ",dir=%s", path);
+	free_page((unsigned long)tmp_page);
+out:
+	return rc;
+}
+
+struct super_operations ecryptfs_sops = {
+	.alloc_inode = ecryptfs_alloc_inode,
+	.destroy_inode = ecryptfs_destroy_inode,
+	.drop_inode = generic_delete_inode,
+	.put_super = ecryptfs_put_super,
+	.statfs = ecryptfs_statfs,
+	.remount_fs = NULL,
+	.clear_inode = ecryptfs_clear_inode,
+	.umount_begin = ecryptfs_umount_begin,
+	.show_options = ecryptfs_show_options
+};
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
new file mode 100644
index 0000000..8c27de8
--- /dev/null
+++ b/fs/gfs2/Kconfig
@@ -0,0 +1,44 @@
+config GFS2_FS
+	tristate "GFS2 file system support"
+	depends on EXPERIMENTAL
+	select FS_POSIX_ACL
+	help
+	A cluster filesystem.
+
+	Allows a cluster of computers to simultaneously use a block device
+	that is shared between them (with FC, iSCSI, NBD, etc...).  GFS reads
+	and writes to the block device like a local filesystem, but also uses
+	a lock module to allow the computers coordinate their I/O so
+	filesystem consistency is maintained.  One of the nifty features of
+	GFS is perfect consistency -- changes made to the filesystem on one
+	machine show up immediately on all other machines in the cluster.
+
+	To use the GFS2 filesystem, you will need to enable one or more of
+	the below locking modules. Documentation and utilities for GFS2 can
+	be found here: http://sources.redhat.com/cluster
+
+config GFS2_FS_LOCKING_NOLOCK
+	tristate "GFS2 \"nolock\" locking module"
+	depends on GFS2_FS
+	help
+	Single node locking module for GFS2.
+
+	Use this module if you want to use GFS2 on a single node without
+	its clustering features. You can still take advantage of the
+	large file support, and upgrade to running a full cluster later on
+	if required.
+
+	If you will only be using GFS2 in cluster mode, you do not need this
+	module.
+
+config GFS2_FS_LOCKING_DLM
+	tristate "GFS2 DLM locking module"
+	depends on GFS2_FS
+	select DLM
+	help
+	Multiple node locking module for GFS2
+
+	Most users of GFS2 will require this module. It provides the locking
+	interface between GFS2 and the DLM, which is required to use GFS2
+	in a cluster environment.
+
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile
new file mode 100644
index 0000000..e3f1ada
--- /dev/null
+++ b/fs/gfs2/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_GFS2_FS) += gfs2.o
+gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \
+	glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \
+	mount.o ondisk.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
+	ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \
+	recovery.o rgrp.o super.o sys.o trans.o util.o
+
+obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/
+obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/
+
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
new file mode 100644
index 0000000..5f959b8
--- /dev/null
+++ b/fs/gfs2/acl.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "trans.h"
+#include "util.h"
+
+#define ACL_ACCESS 1
+#define ACL_DEFAULT 0
+
+int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
+		      struct gfs2_ea_request *er,
+		      int *remove, mode_t *mode)
+{
+	struct posix_acl *acl;
+	int error;
+
+	error = gfs2_acl_validate_remove(ip, access);
+	if (error)
+		return error;
+
+	if (!er->er_data)
+		return -EINVAL;
+
+	acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
+	if (IS_ERR(acl))
+		return PTR_ERR(acl);
+	if (!acl) {
+		*remove = 1;
+		return 0;
+	}
+
+	error = posix_acl_valid(acl);
+	if (error)
+		goto out;
+
+	if (access) {
+		error = posix_acl_equiv_mode(acl, mode);
+		if (!error)
+			*remove = 1;
+		else if (error > 0)
+			error = 0;
+	}
+
+out:
+	posix_acl_release(acl);
+	return error;
+}
+
+int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
+{
+	if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
+		return -EOPNOTSUPP;
+	if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER))
+		return -EPERM;
+	if (S_ISLNK(ip->i_di.di_mode))
+		return -EOPNOTSUPP;
+	if (!access && !S_ISDIR(ip->i_di.di_mode))
+		return -EACCES;
+
+	return 0;
+}
+
+static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
+		   struct gfs2_ea_location *el, char **data, unsigned int *len)
+{
+	struct gfs2_ea_request er;
+	struct gfs2_ea_location el_this;
+	int error;
+
+	if (!ip->i_di.di_eattr)
+		return 0;
+
+	memset(&er, 0, sizeof(struct gfs2_ea_request));
+	if (access) {
+		er.er_name = GFS2_POSIX_ACL_ACCESS;
+		er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
+	} else {
+		er.er_name = GFS2_POSIX_ACL_DEFAULT;
+		er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
+	}
+	er.er_type = GFS2_EATYPE_SYS;
+
+	if (!el)
+		el = &el_this;
+
+	error = gfs2_ea_find(ip, &er, el);
+	if (error)
+		return error;
+	if (!el->el_ea)
+		return 0;
+	if (!GFS2_EA_DATA_LEN(el->el_ea))
+		goto out;
+
+	er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
+	er.er_data = kmalloc(er.er_data_len, GFP_KERNEL);
+	error = -ENOMEM;
+	if (!er.er_data)
+		goto out;
+
+	error = gfs2_ea_get_copy(ip, el, er.er_data);
+	if (error)
+		goto out_kfree;
+
+	if (acl) {
+		*acl = posix_acl_from_xattr(er.er_data, er.er_data_len);
+		if (IS_ERR(*acl))
+			error = PTR_ERR(*acl);
+	}
+
+out_kfree:
+	if (error || !data)
+		kfree(er.er_data);
+	else {
+		*data = er.er_data;
+		*len = er.er_data_len;
+	}
+out:
+	if (error || el == &el_this)
+		brelse(el->el_bh);
+	return error;
+}
+
+/**
+ * gfs2_check_acl_locked - Check an ACL to see if we're allowed to do something
+ * @inode: the file we want to do something to
+ * @mask: what we want to do
+ *
+ * Returns: errno
+ */
+
+int gfs2_check_acl_locked(struct inode *inode, int mask)
+{
+	struct posix_acl *acl = NULL;
+	int error;
+
+	error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL);
+	if (error)
+		return error;
+
+	if (acl) {
+		error = posix_acl_permission(inode, acl, mask);
+		posix_acl_release(acl);
+		return error;
+	}
+
+	return -EAGAIN;
+}
+
+int gfs2_check_acl(struct inode *inode, int mask)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder i_gh;
+	int error;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+	if (!error) {
+		error = gfs2_check_acl_locked(inode, mask);
+		gfs2_glock_dq_uninit(&i_gh);
+	}
+
+	return error;
+}
+
+static int munge_mode(struct gfs2_inode *ip, mode_t mode)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+	if (error)
+		return error;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		gfs2_assert_withdraw(sdp,
+				(ip->i_di.di_mode & S_IFMT) == (mode & S_IFMT));
+		ip->i_di.di_mode = mode;
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(sdp);
+
+	return 0;
+}
+
+int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct posix_acl *acl = NULL, *clone;
+	struct gfs2_ea_request er;
+	mode_t mode = ip->i_di.di_mode;
+	int error;
+
+	if (!sdp->sd_args.ar_posix_acl)
+		return 0;
+	if (S_ISLNK(ip->i_di.di_mode))
+		return 0;
+
+	memset(&er, 0, sizeof(struct gfs2_ea_request));
+	er.er_type = GFS2_EATYPE_SYS;
+
+	error = acl_get(dip, ACL_DEFAULT, &acl, NULL,
+			&er.er_data, &er.er_data_len);
+	if (error)
+		return error;
+	if (!acl) {
+		mode &= ~current->fs->umask;
+		if (mode != ip->i_di.di_mode)
+			error = munge_mode(ip, mode);
+		return error;
+	}
+
+	clone = posix_acl_clone(acl, GFP_KERNEL);
+	error = -ENOMEM;
+	if (!clone)
+		goto out;
+	posix_acl_release(acl);
+	acl = clone;
+
+	if (S_ISDIR(ip->i_di.di_mode)) {
+		er.er_name = GFS2_POSIX_ACL_DEFAULT;
+		er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
+		error = gfs2_system_eaops.eo_set(ip, &er);
+		if (error)
+			goto out;
+	}
+
+	error = posix_acl_create_masq(acl, &mode);
+	if (error < 0)
+		goto out;
+	if (error > 0) {
+		er.er_name = GFS2_POSIX_ACL_ACCESS;
+		er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
+		posix_acl_to_xattr(acl, er.er_data, er.er_data_len);
+		er.er_mode = mode;
+		er.er_flags = GFS2_ERF_MODE;
+		error = gfs2_system_eaops.eo_set(ip, &er);
+		if (error)
+			goto out;
+	} else
+		munge_mode(ip, mode);
+
+out:
+	posix_acl_release(acl);
+	kfree(er.er_data);
+	return error;
+}
+
+int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
+{
+	struct posix_acl *acl = NULL, *clone;
+	struct gfs2_ea_location el;
+	char *data;
+	unsigned int len;
+	int error;
+
+	error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len);
+	if (error)
+		return error;
+	if (!acl)
+		return gfs2_setattr_simple(ip, attr);
+
+	clone = posix_acl_clone(acl, GFP_KERNEL);
+	error = -ENOMEM;
+	if (!clone)
+		goto out;
+	posix_acl_release(acl);
+	acl = clone;
+
+	error = posix_acl_chmod_masq(acl, attr->ia_mode);
+	if (!error) {
+		posix_acl_to_xattr(acl, data, len);
+		error = gfs2_ea_acl_chmod(ip, &el, attr, data);
+	}
+
+out:
+	posix_acl_release(acl);
+	brelse(el.el_bh);
+	kfree(data);
+	return error;
+}
+
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
new file mode 100644
index 0000000..05c294f
--- /dev/null
+++ b/fs/gfs2/acl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __ACL_DOT_H__
+#define __ACL_DOT_H__
+
+#include "incore.h"
+
+#define GFS2_POSIX_ACL_ACCESS		"posix_acl_access"
+#define GFS2_POSIX_ACL_ACCESS_LEN	16
+#define GFS2_POSIX_ACL_DEFAULT		"posix_acl_default"
+#define GFS2_POSIX_ACL_DEFAULT_LEN	17
+
+#define GFS2_ACL_IS_ACCESS(name, len) \
+         ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \
+         !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len)))
+
+#define GFS2_ACL_IS_DEFAULT(name, len) \
+         ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \
+         !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len)))
+
+struct gfs2_ea_request;
+
+int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
+			  struct gfs2_ea_request *er,
+			  int *remove, mode_t *mode);
+int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access);
+int gfs2_check_acl_locked(struct inode *inode, int mask);
+int gfs2_check_acl(struct inode *inode, int mask);
+int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
+int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
+
+#endif /* __ACL_DOT_H__ */
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
new file mode 100644
index 0000000..cc57f2e
--- /dev/null
+++ b/fs/gfs2/bmap.c
@@ -0,0 +1,1221 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "dir.h"
+#include "util.h"
+#include "ops_address.h"
+
+/* This doesn't need to be that large as max 64 bit pointers in a 4k
+ * block is 512, so __u16 is fine for that. It saves stack space to
+ * keep it small.
+ */
+struct metapath {
+	__u16 mp_list[GFS2_MAX_META_HEIGHT];
+};
+
+typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh,
+			     struct buffer_head *bh, u64 *top,
+			     u64 *bottom, unsigned int height,
+			     void *data);
+
+struct strip_mine {
+	int sm_first;
+	unsigned int sm_height;
+};
+
+/**
+ * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @block: the block number that was allocated
+ * @private: any locked page held by the caller process
+ *
+ * Returns: errno
+ */
+
+static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
+			       u64 block, struct page *page)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct inode *inode = &ip->i_inode;
+	struct buffer_head *bh;
+	int release = 0;
+
+	if (!page || page->index) {
+		page = grab_cache_page(inode->i_mapping, 0);
+		if (!page)
+			return -ENOMEM;
+		release = 1;
+	}
+
+	if (!PageUptodate(page)) {
+		void *kaddr = kmap(page);
+
+		memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
+		       ip->i_di.di_size);
+		memset(kaddr + ip->i_di.di_size, 0,
+		       PAGE_CACHE_SIZE - ip->i_di.di_size);
+		kunmap(page);
+
+		SetPageUptodate(page);
+	}
+
+	if (!page_has_buffers(page))
+		create_empty_buffers(page, 1 << inode->i_blkbits,
+				     (1 << BH_Uptodate));
+
+	bh = page_buffers(page);
+
+	if (!buffer_mapped(bh))
+		map_bh(bh, inode->i_sb, block);
+
+	set_buffer_uptodate(bh);
+	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+		gfs2_trans_add_bh(ip->i_gl, bh, 0);
+	mark_buffer_dirty(bh);
+
+	if (release) {
+		unlock_page(page);
+		page_cache_release(page);
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big
+ * @ip: The GFS2 inode to unstuff
+ * @unstuffer: the routine that handles unstuffing a non-zero length file
+ * @private: private data for the unstuffer
+ *
+ * This routine unstuffs a dinode and returns it to a "normal" state such
+ * that the height can be grown in the traditional way.
+ *
+ * Returns: errno
+ */
+
+int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
+{
+	struct buffer_head *bh, *dibh;
+	struct gfs2_dinode *di;
+	u64 block = 0;
+	int isdir = gfs2_is_dir(ip);
+	int error;
+
+	down_write(&ip->i_rw_mutex);
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto out;
+
+	if (ip->i_di.di_size) {
+		/* Get a free block, fill it with the stuffed data,
+		   and write it out to disk */
+
+		if (isdir) {
+			block = gfs2_alloc_meta(ip);
+
+			error = gfs2_dir_get_new_buffer(ip, block, &bh);
+			if (error)
+				goto out_brelse;
+			gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_meta_header),
+					      dibh, sizeof(struct gfs2_dinode));
+			brelse(bh);
+		} else {
+			block = gfs2_alloc_data(ip);
+
+			error = gfs2_unstuffer_page(ip, dibh, block, page);
+			if (error)
+				goto out_brelse;
+		}
+	}
+
+	/*  Set up the pointer to the new block  */
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	di = (struct gfs2_dinode *)dibh->b_data;
+	gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+
+	if (ip->i_di.di_size) {
+		*(__be64 *)(di + 1) = cpu_to_be64(block);
+		ip->i_di.di_blocks++;
+		di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
+	}
+
+	ip->i_di.di_height = 1;
+	di->di_height = cpu_to_be16(1);
+
+out_brelse:
+	brelse(dibh);
+out:
+	up_write(&ip->i_rw_mutex);
+	return error;
+}
+
+/**
+ * calc_tree_height - Calculate the height of a metadata tree
+ * @ip: The GFS2 inode
+ * @size: The proposed size of the file
+ *
+ * Work out how tall a metadata tree needs to be in order to accommodate a
+ * file of a particular size. If size is less than the current size of
+ * the inode, then the current size of the inode is used instead of the
+ * supplied one.
+ *
+ * Returns: the height the tree should be
+ */
+
+static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	u64 *arr;
+	unsigned int max, height;
+
+	if (ip->i_di.di_size > size)
+		size = ip->i_di.di_size;
+
+	if (gfs2_is_dir(ip)) {
+		arr = sdp->sd_jheightsize;
+		max = sdp->sd_max_jheight;
+	} else {
+		arr = sdp->sd_heightsize;
+		max = sdp->sd_max_height;
+	}
+
+	for (height = 0; height < max; height++)
+		if (arr[height] >= size)
+			break;
+
+	return height;
+}
+
+/**
+ * build_height - Build a metadata tree of the requested height
+ * @ip: The GFS2 inode
+ * @height: The height to build to
+ *
+ *
+ * Returns: errno
+ */
+
+static int build_height(struct inode *inode, unsigned height)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	unsigned new_height = height - ip->i_di.di_height;
+	struct buffer_head *dibh;
+	struct buffer_head *blocks[GFS2_MAX_META_HEIGHT];
+	struct gfs2_dinode *di;
+	int error;
+	u64 *bp;
+	u64 bn;
+	unsigned n;
+
+	if (height <= ip->i_di.di_height)
+		return 0;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		return error;
+
+	for(n = 0; n < new_height; n++) {
+		bn = gfs2_alloc_meta(ip);
+		blocks[n] = gfs2_meta_new(ip->i_gl, bn);
+		gfs2_trans_add_bh(ip->i_gl, blocks[n], 1);
+	}
+
+	n = 0;
+	bn = blocks[0]->b_blocknr;
+	if (new_height > 1) {
+		for(; n < new_height-1; n++) {
+			gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN,
+					  GFS2_FORMAT_IN);
+			gfs2_buffer_clear_tail(blocks[n],
+					       sizeof(struct gfs2_meta_header));
+			bp = (u64 *)(blocks[n]->b_data +
+				     sizeof(struct gfs2_meta_header));
+			*bp = cpu_to_be64(blocks[n+1]->b_blocknr);
+			brelse(blocks[n]);
+			blocks[n] = NULL;
+		}
+	}
+	gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+	gfs2_buffer_copy_tail(blocks[n], sizeof(struct gfs2_meta_header),
+			      dibh, sizeof(struct gfs2_dinode));
+	brelse(blocks[n]);
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	di = (struct gfs2_dinode *)dibh->b_data;
+	gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+	*(__be64 *)(di + 1) = cpu_to_be64(bn);
+	ip->i_di.di_height += new_height;
+	ip->i_di.di_blocks += new_height;
+	di->di_height = cpu_to_be16(ip->i_di.di_height);
+	di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
+	brelse(dibh);
+	return error;
+}
+
+/**
+ * find_metapath - Find path through the metadata tree
+ * @ip: The inode pointer
+ * @mp: The metapath to return the result in
+ * @block: The disk block to look up
+ *
+ *   This routine returns a struct metapath structure that defines a path
+ *   through the metadata of inode "ip" to get to block "block".
+ *
+ *   Example:
+ *   Given:  "ip" is a height 3 file, "offset" is 101342453, and this is a
+ *   filesystem with a blocksize of 4096.
+ *
+ *   find_metapath() would return a struct metapath structure set to:
+ *   mp_offset = 101342453, mp_height = 3, mp_list[0] = 0, mp_list[1] = 48,
+ *   and mp_list[2] = 165.
+ *
+ *   That means that in order to get to the block containing the byte at
+ *   offset 101342453, we would load the indirect block pointed to by pointer
+ *   0 in the dinode.  We would then load the indirect block pointed to by
+ *   pointer 48 in that indirect block.  We would then load the data block
+ *   pointed to by pointer 165 in that indirect block.
+ *
+ *             ----------------------------------------
+ *             | Dinode |                             |
+ *             |        |                            4|
+ *             |        |0 1 2 3 4 5                 9|
+ *             |        |                            6|
+ *             ----------------------------------------
+ *                       |
+ *                       |
+ *                       V
+ *             ----------------------------------------
+ *             | Indirect Block                       |
+ *             |                                     5|
+ *             |            4 4 4 4 4 5 5            1|
+ *             |0           5 6 7 8 9 0 1            2|
+ *             ----------------------------------------
+ *                                |
+ *                                |
+ *                                V
+ *             ----------------------------------------
+ *             | Indirect Block                       |
+ *             |                         1 1 1 1 1   5|
+ *             |                         6 6 6 6 6   1|
+ *             |0                        3 4 5 6 7   2|
+ *             ----------------------------------------
+ *                                           |
+ *                                           |
+ *                                           V
+ *             ----------------------------------------
+ *             | Data block containing offset         |
+ *             |            101342453                 |
+ *             |                                      |
+ *             |                                      |
+ *             ----------------------------------------
+ *
+ */
+
+static void find_metapath(struct gfs2_inode *ip, u64 block,
+			  struct metapath *mp)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	u64 b = block;
+	unsigned int i;
+
+	for (i = ip->i_di.di_height; i--;)
+		mp->mp_list[i] = do_div(b, sdp->sd_inptrs);
+
+}
+
+/**
+ * metapointer - Return pointer to start of metadata in a buffer
+ * @bh: The buffer
+ * @height: The metadata height (0 = dinode)
+ * @mp: The metapath
+ *
+ * Return a pointer to the block number of the next height of the metadata
+ * tree given a buffer containing the pointer to the current height of the
+ * metadata tree.
+ */
+
+static inline u64 *metapointer(struct buffer_head *bh, int *boundary,
+			       unsigned int height, const struct metapath *mp)
+{
+	unsigned int head_size = (height > 0) ?
+		sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
+	u64 *ptr;
+	*boundary = 0;
+	ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height];
+	if (ptr + 1 == (u64 *)(bh->b_data + bh->b_size))
+		*boundary = 1;
+	return ptr;
+}
+
+/**
+ * lookup_block - Get the next metadata block in metadata tree
+ * @ip: The GFS2 inode
+ * @bh: Buffer containing the pointers to metadata blocks
+ * @height: The height of the tree (0 = dinode)
+ * @mp: The metapath
+ * @create: Non-zero if we may create a new meatdata block
+ * @new: Used to indicate if we did create a new metadata block
+ * @block: the returned disk block number
+ *
+ * Given a metatree, complete to a particular height, checks to see if the next
+ * height of the tree exists. If not the next height of the tree is created.
+ * The block number of the next height of the metadata tree is returned.
+ *
+ */
+
+static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
+			unsigned int height, struct metapath *mp, int create,
+			int *new, u64 *block)
+{
+	int boundary;
+	u64 *ptr = metapointer(bh, &boundary, height, mp);
+
+	if (*ptr) {
+		*block = be64_to_cpu(*ptr);
+		return boundary;
+	}
+
+	*block = 0;
+
+	if (!create)
+		return 0;
+
+	if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip))
+		*block = gfs2_alloc_data(ip);
+	else
+		*block = gfs2_alloc_meta(ip);
+
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+	*ptr = cpu_to_be64(*block);
+	ip->i_di.di_blocks++;
+
+	*new = 1;
+	return 0;
+}
+
+/**
+ * gfs2_block_pointers - Map a block from an inode to a disk block
+ * @inode: The inode
+ * @lblock: The logical block number
+ * @map_bh: The bh to be mapped
+ * @mp: metapath to use
+ *
+ * Find the block number on the current device which corresponds to an
+ * inode's block. If the block had to be created, "new" will be set.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
+			       struct buffer_head *bh_map, struct metapath *mp,
+			       unsigned int maxlen)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct buffer_head *bh;
+	unsigned int bsize;
+	unsigned int height;
+	unsigned int end_of_metadata;
+	unsigned int x;
+	int error = 0;
+	int new = 0;
+	u64 dblock = 0;
+	int boundary;
+
+	BUG_ON(maxlen == 0);
+
+	if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
+		return 0;
+
+	bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize;
+
+	height = calc_tree_height(ip, (lblock + 1) * bsize);
+	if (ip->i_di.di_height < height) {
+		if (!create)
+			return 0;
+
+		error = build_height(inode, height);
+		if (error)
+			return error;
+	}
+
+	find_metapath(ip, lblock, mp);
+	end_of_metadata = ip->i_di.di_height - 1;
+
+	error = gfs2_meta_inode_buffer(ip, &bh);
+	if (error)
+		return error;
+
+	for (x = 0; x < end_of_metadata; x++) {
+		lookup_block(ip, bh, x, mp, create, &new, &dblock);
+		brelse(bh);
+		if (!dblock)
+			return 0;
+
+		error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh);
+		if (error)
+			return error;
+	}
+
+	boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock);
+	clear_buffer_mapped(bh_map);
+	clear_buffer_new(bh_map);
+	clear_buffer_boundary(bh_map);
+
+	if (dblock) {
+		map_bh(bh_map, inode->i_sb, dblock);
+		if (boundary)
+			set_buffer_boundary(bh);
+		if (new) {
+			struct buffer_head *dibh;
+			error = gfs2_meta_inode_buffer(ip, &dibh);
+			if (!error) {
+				gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+				gfs2_dinode_out(&ip->i_di, dibh->b_data);
+				brelse(dibh);
+			}
+			set_buffer_new(bh_map);
+			goto out_brelse;
+		}
+		while(--maxlen && !buffer_boundary(bh_map)) {
+			u64 eblock;
+
+			mp->mp_list[end_of_metadata]++;
+			boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock);
+			if (eblock != ++dblock)
+				break;
+			bh_map->b_size += (1 << inode->i_blkbits);
+			if (boundary)
+				set_buffer_boundary(bh_map);
+		}
+	}
+out_brelse:
+	brelse(bh);
+	return 0;
+}
+
+
+static inline void bmap_lock(struct inode *inode, int create)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	if (create)
+		down_write(&ip->i_rw_mutex);
+	else
+		down_read(&ip->i_rw_mutex);
+}
+
+static inline void bmap_unlock(struct inode *inode, int create)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	if (create)
+		up_write(&ip->i_rw_mutex);
+	else
+		up_read(&ip->i_rw_mutex);
+}
+
+int gfs2_block_map(struct inode *inode, u64 lblock, int create,
+		   struct buffer_head *bh, unsigned int maxlen)
+{
+	struct metapath mp;
+	int ret;
+
+	bmap_lock(inode, create);
+	ret = gfs2_block_pointers(inode, lblock, create, bh, &mp, maxlen);
+	bmap_unlock(inode, create);
+	return ret;
+}
+
+int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
+{
+	struct metapath mp;
+	struct buffer_head bh = { .b_state = 0, .b_blocknr = 0, .b_size = 0 };
+	int ret;
+	int create = *new;
+
+	BUG_ON(!extlen);
+	BUG_ON(!dblock);
+	BUG_ON(!new);
+
+	bmap_lock(inode, create);
+	ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp, 32);
+	bmap_unlock(inode, create);
+	*extlen = bh.b_size >> inode->i_blkbits;
+	*dblock = bh.b_blocknr;
+	if (buffer_new(&bh))
+		*new = 1;
+	else
+		*new = 0;
+	return ret;
+}
+
+/**
+ * recursive_scan - recursively scan through the end of a file
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @mp: the path through the metadata to the point to start
+ * @height: the height the recursion is at
+ * @block: the indirect block to look at
+ * @first: 1 if this is the first block
+ * @bc: the call to make for each piece of metadata
+ * @data: data opaque to this function to pass to @bc
+ *
+ * When this is first called @height and @block should be zero and
+ * @first should be 1.
+ *
+ * Returns: errno
+ */
+
+static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
+			  struct metapath *mp, unsigned int height,
+			  u64 block, int first, block_call_t bc,
+			  void *data)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head *bh = NULL;
+	u64 *top, *bottom;
+	u64 bn;
+	int error;
+	int mh_size = sizeof(struct gfs2_meta_header);
+
+	if (!height) {
+		error = gfs2_meta_inode_buffer(ip, &bh);
+		if (error)
+			return error;
+		dibh = bh;
+
+		top = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
+		bottom = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
+	} else {
+		error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
+		if (error)
+			return error;
+
+		top = (u64 *)(bh->b_data + mh_size) +
+				  (first ? mp->mp_list[height] : 0);
+
+		bottom = (u64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
+	}
+
+	error = bc(ip, dibh, bh, top, bottom, height, data);
+	if (error)
+		goto out;
+
+	if (height < ip->i_di.di_height - 1)
+		for (; top < bottom; top++, first = 0) {
+			if (!*top)
+				continue;
+
+			bn = be64_to_cpu(*top);
+
+			error = recursive_scan(ip, dibh, mp, height + 1, bn,
+					       first, bc, data);
+			if (error)
+				break;
+		}
+
+out:
+	brelse(bh);
+	return error;
+}
+
+/**
+ * do_strip - Look for a layer a particular layer of the file and strip it off
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @bh: A buffer of pointers
+ * @top: The first pointer in the buffer
+ * @bottom: One more than the last pointer
+ * @height: the height this buffer is at
+ * @data: a pointer to a struct strip_mine
+ *
+ * Returns: errno
+ */
+
+static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
+		    struct buffer_head *bh, u64 *top, u64 *bottom,
+		    unsigned int height, void *data)
+{
+	struct strip_mine *sm = data;
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_rgrp_list rlist;
+	u64 bn, bstart;
+	u32 blen;
+	u64 *p;
+	unsigned int rg_blocks = 0;
+	int metadata;
+	unsigned int revokes = 0;
+	int x;
+	int error;
+
+	if (!*top)
+		sm->sm_first = 0;
+
+	if (height != sm->sm_height)
+		return 0;
+
+	if (sm->sm_first) {
+		top++;
+		sm->sm_first = 0;
+	}
+
+	metadata = (height != ip->i_di.di_height - 1);
+	if (metadata)
+		revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
+
+	error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh);
+	if (error)
+		return error;
+
+	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
+	bstart = 0;
+	blen = 0;
+
+	for (p = top; p < bottom; p++) {
+		if (!*p)
+			continue;
+
+		bn = be64_to_cpu(*p);
+
+		if (bstart + blen == bn)
+			blen++;
+		else {
+			if (bstart)
+				gfs2_rlist_add(sdp, &rlist, bstart);
+
+			bstart = bn;
+			blen = 1;
+		}
+	}
+
+	if (bstart)
+		gfs2_rlist_add(sdp, &rlist, bstart);
+	else
+		goto out; /* Nothing to do */
+
+	gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
+
+	for (x = 0; x < rlist.rl_rgrps; x++) {
+		struct gfs2_rgrpd *rgd;
+		rgd = rlist.rl_ghs[x].gh_gl->gl_object;
+		rg_blocks += rgd->rd_ri.ri_length;
+	}
+
+	error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
+	if (error)
+		goto out_rlist;
+
+	error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
+				 RES_INDIRECT + RES_STATFS + RES_QUOTA,
+				 revokes);
+	if (error)
+		goto out_rg_gunlock;
+
+	down_write(&ip->i_rw_mutex);
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+	bstart = 0;
+	blen = 0;
+
+	for (p = top; p < bottom; p++) {
+		if (!*p)
+			continue;
+
+		bn = be64_to_cpu(*p);
+
+		if (bstart + blen == bn)
+			blen++;
+		else {
+			if (bstart) {
+				if (metadata)
+					gfs2_free_meta(ip, bstart, blen);
+				else
+					gfs2_free_data(ip, bstart, blen);
+			}
+
+			bstart = bn;
+			blen = 1;
+		}
+
+		*p = 0;
+		if (!ip->i_di.di_blocks)
+			gfs2_consist_inode(ip);
+		ip->i_di.di_blocks--;
+	}
+	if (bstart) {
+		if (metadata)
+			gfs2_free_meta(ip, bstart, blen);
+		else
+			gfs2_free_data(ip, bstart, blen);
+	}
+
+	ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+
+	up_write(&ip->i_rw_mutex);
+
+	gfs2_trans_end(sdp);
+
+out_rg_gunlock:
+	gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
+out_rlist:
+	gfs2_rlist_free(&rlist);
+out:
+	gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh);
+	return error;
+}
+
+/**
+ * do_grow - Make a file look bigger than it is
+ * @ip: the inode
+ * @size: the size to set the file to
+ *
+ * Called with an exclusive lock on @ip.
+ *
+ * Returns: errno
+ */
+
+static int do_grow(struct gfs2_inode *ip, u64 size)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al;
+	struct buffer_head *dibh;
+	unsigned int h;
+	int error;
+
+	al = gfs2_alloc_get(ip);
+
+	error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out;
+
+	error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+	if (error)
+		goto out_gunlock_q;
+
+	al->al_requested = sdp->sd_max_height + RES_DATA;
+
+	error = gfs2_inplace_reserve(ip);
+	if (error)
+		goto out_gunlock_q;
+
+	error = gfs2_trans_begin(sdp,
+			sdp->sd_max_height + al->al_rgd->rd_ri.ri_length +
+			RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0);
+	if (error)
+		goto out_ipres;
+
+	if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
+		if (gfs2_is_stuffed(ip)) {
+			error = gfs2_unstuff_dinode(ip, NULL);
+			if (error)
+				goto out_end_trans;
+		}
+
+		h = calc_tree_height(ip, size);
+		if (ip->i_di.di_height < h) {
+			down_write(&ip->i_rw_mutex);
+			error = build_height(&ip->i_inode, h);
+			up_write(&ip->i_rw_mutex);
+			if (error)
+				goto out_end_trans;
+		}
+	}
+
+	ip->i_di.di_size = size;
+	ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto out_end_trans;
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
+
+out_end_trans:
+	gfs2_trans_end(sdp);
+out_ipres:
+	gfs2_inplace_release(ip);
+out_gunlock_q:
+	gfs2_quota_unlock(ip);
+out:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
+
+/**
+ * gfs2_block_truncate_page - Deal with zeroing out data for truncate
+ *
+ * This is partly borrowed from ext3.
+ */
+static int gfs2_block_truncate_page(struct address_space *mapping)
+{
+	struct inode *inode = mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	loff_t from = inode->i_size;
+	unsigned long index = from >> PAGE_CACHE_SHIFT;
+	unsigned offset = from & (PAGE_CACHE_SIZE-1);
+	unsigned blocksize, iblock, length, pos;
+	struct buffer_head *bh;
+	struct page *page;
+	void *kaddr;
+	int err;
+
+	page = grab_cache_page(mapping, index);
+	if (!page)
+		return 0;
+
+	blocksize = inode->i_sb->s_blocksize;
+	length = blocksize - (offset & (blocksize - 1));
+	iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+
+	if (!page_has_buffers(page))
+		create_empty_buffers(page, blocksize, 0);
+
+	/* Find the buffer that contains "offset" */
+	bh = page_buffers(page);
+	pos = blocksize;
+	while (offset >= pos) {
+		bh = bh->b_this_page;
+		iblock++;
+		pos += blocksize;
+	}
+
+	err = 0;
+
+	if (!buffer_mapped(bh)) {
+		gfs2_get_block(inode, iblock, bh, 0);
+		/* unmapped? It's a hole - nothing to do */
+		if (!buffer_mapped(bh))
+			goto unlock;
+	}
+
+	/* Ok, it's mapped. Make sure it's up-to-date */
+	if (PageUptodate(page))
+		set_buffer_uptodate(bh);
+
+	if (!buffer_uptodate(bh)) {
+		err = -EIO;
+		ll_rw_block(READ, 1, &bh);
+		wait_on_buffer(bh);
+		/* Uhhuh. Read error. Complain and punt. */
+		if (!buffer_uptodate(bh))
+			goto unlock;
+	}
+
+	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+		gfs2_trans_add_bh(ip->i_gl, bh, 0);
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	memset(kaddr + offset, 0, length);
+	flush_dcache_page(page);
+	kunmap_atomic(kaddr, KM_USER0);
+
+unlock:
+	unlock_page(page);
+	page_cache_release(page);
+	return err;
+}
+
+static int trunc_start(struct gfs2_inode *ip, u64 size)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head *dibh;
+	int journaled = gfs2_is_jdata(ip);
+	int error;
+
+	error = gfs2_trans_begin(sdp,
+				 RES_DINODE + (journaled ? RES_JDATA : 0), 0);
+	if (error)
+		return error;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto out;
+
+	if (gfs2_is_stuffed(ip)) {
+		ip->i_di.di_size = size;
+		ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);
+		error = 1;
+
+	} else {
+		if (size & (u64)(sdp->sd_sb.sb_bsize - 1))
+			error = gfs2_block_truncate_page(ip->i_inode.i_mapping);
+
+		if (!error) {
+			ip->i_di.di_size = size;
+			ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+			ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG;
+			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+			gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		}
+	}
+
+	brelse(dibh);
+
+out:
+	gfs2_trans_end(sdp);
+	return error;
+}
+
+static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
+{
+	unsigned int height = ip->i_di.di_height;
+	u64 lblock;
+	struct metapath mp;
+	int error;
+
+	if (!size)
+		lblock = 0;
+	else
+		lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift;
+
+	find_metapath(ip, lblock, &mp);
+	gfs2_alloc_get(ip);
+
+	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out;
+
+	while (height--) {
+		struct strip_mine sm;
+		sm.sm_first = !!size;
+		sm.sm_height = height;
+
+		error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);
+		if (error)
+			break;
+	}
+
+	gfs2_quota_unhold(ip);
+
+out:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
+static int trunc_end(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+	if (error)
+		return error;
+
+	down_write(&ip->i_rw_mutex);
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto out;
+
+	if (!ip->i_di.di_size) {
+		ip->i_di.di_height = 0;
+		ip->i_di.di_goal_meta =
+			ip->i_di.di_goal_data =
+			ip->i_num.no_addr;
+		gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+	}
+	ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+	ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG;
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
+
+out:
+	up_write(&ip->i_rw_mutex);
+	gfs2_trans_end(sdp);
+	return error;
+}
+
+/**
+ * do_shrink - make a file smaller
+ * @ip: the inode
+ * @size: the size to make the file
+ * @truncator: function to truncate the last partial block
+ *
+ * Called with an exclusive lock on @ip.
+ *
+ * Returns: errno
+ */
+
+static int do_shrink(struct gfs2_inode *ip, u64 size)
+{
+	int error;
+
+	error = trunc_start(ip, size);
+	if (error < 0)
+		return error;
+	if (error > 0)
+		return 0;
+
+	error = trunc_dealloc(ip, size);
+	if (!error)
+		error = trunc_end(ip);
+
+	return error;
+}
+
+/**
+ * gfs2_truncatei - make a file a given size
+ * @ip: the inode
+ * @size: the size to make the file
+ * @truncator: function to truncate the last partial block
+ *
+ * The file size can grow, shrink, or stay the same size.
+ *
+ * Returns: errno
+ */
+
+int gfs2_truncatei(struct gfs2_inode *ip, u64 size)
+{
+	int error;
+
+	if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_di.di_mode)))
+		return -EINVAL;
+
+	if (size > ip->i_di.di_size)
+		error = do_grow(ip, size);
+	else
+		error = do_shrink(ip, size);
+
+	return error;
+}
+
+int gfs2_truncatei_resume(struct gfs2_inode *ip)
+{
+	int error;
+	error = trunc_dealloc(ip, ip->i_di.di_size);
+	if (!error)
+		error = trunc_end(ip);
+	return error;
+}
+
+int gfs2_file_dealloc(struct gfs2_inode *ip)
+{
+	return trunc_dealloc(ip, 0);
+}
+
+/**
+ * gfs2_write_calc_reserv - calculate number of blocks needed to write to a file
+ * @ip: the file
+ * @len: the number of bytes to be written to the file
+ * @data_blocks: returns the number of data blocks required
+ * @ind_blocks: returns the number of indirect blocks required
+ *
+ */
+
+void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
+			    unsigned int *data_blocks, unsigned int *ind_blocks)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	unsigned int tmp;
+
+	if (gfs2_is_dir(ip)) {
+		*data_blocks = DIV_ROUND_UP(len, sdp->sd_jbsize) + 2;
+		*ind_blocks = 3 * (sdp->sd_max_jheight - 1);
+	} else {
+		*data_blocks = (len >> sdp->sd_sb.sb_bsize_shift) + 3;
+		*ind_blocks = 3 * (sdp->sd_max_height - 1);
+	}
+
+	for (tmp = *data_blocks; tmp > sdp->sd_diptrs;) {
+		tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
+		*ind_blocks += tmp;
+	}
+}
+
+/**
+ * gfs2_write_alloc_required - figure out if a write will require an allocation
+ * @ip: the file being written to
+ * @offset: the offset to write to
+ * @len: the number of bytes being written
+ * @alloc_required: set to 1 if an alloc is required, 0 otherwise
+ *
+ * Returns: errno
+ */
+
+int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
+			      unsigned int len, int *alloc_required)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	u64 lblock, lblock_stop, dblock;
+	u32 extlen;
+	int new = 0;
+	int error = 0;
+
+	*alloc_required = 0;
+
+	if (!len)
+		return 0;
+
+	if (gfs2_is_stuffed(ip)) {
+		if (offset + len >
+		    sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
+			*alloc_required = 1;
+		return 0;
+	}
+
+	if (gfs2_is_dir(ip)) {
+		unsigned int bsize = sdp->sd_jbsize;
+		lblock = offset;
+		do_div(lblock, bsize);
+		lblock_stop = offset + len + bsize - 1;
+		do_div(lblock_stop, bsize);
+	} else {
+		unsigned int shift = sdp->sd_sb.sb_bsize_shift;
+		lblock = offset >> shift;
+		lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
+	}
+
+	for (; lblock < lblock_stop; lblock += extlen) {
+		error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
+		if (error)
+			return error;
+
+		if (!dblock) {
+			*alloc_required = 1;
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
new file mode 100644
index 0000000..0fd379b
--- /dev/null
+++ b/fs/gfs2/bmap.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __BMAP_DOT_H__
+#define __BMAP_DOT_H__
+
+struct inode;
+struct gfs2_inode;
+struct page;
+
+int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
+int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh, unsigned int maxlen);
+int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
+
+int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
+int gfs2_truncatei_resume(struct gfs2_inode *ip);
+int gfs2_file_dealloc(struct gfs2_inode *ip);
+
+void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
+			    unsigned int *data_blocks,
+			    unsigned int *ind_blocks);
+int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
+			      unsigned int len, int *alloc_required);
+
+#endif /* __BMAP_DOT_H__ */
diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c
new file mode 100644
index 0000000..cab1f68
--- /dev/null
+++ b/fs/gfs2/daemon.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "daemon.h"
+#include "glock.h"
+#include "log.h"
+#include "quota.h"
+#include "recovery.h"
+#include "super.h"
+#include "util.h"
+
+/* This uses schedule_timeout() instead of msleep() because it's good for
+   the daemons to wake up more often than the timeout when unmounting so
+   the user's unmount doesn't sit there forever.
+
+   The kthread functions used to start these daemons block and flush signals. */
+
+/**
+ * gfs2_scand - Look for cached glocks and inodes to toss from memory
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One of these daemons runs, finding candidates to add to sd_reclaim_list.
+ * See gfs2_glockd()
+ */
+
+int gfs2_scand(void *data)
+{
+	struct gfs2_sbd *sdp = data;
+	unsigned long t;
+
+	while (!kthread_should_stop()) {
+		gfs2_scand_internal(sdp);
+		t = gfs2_tune_get(sdp, gt_scand_secs) * HZ;
+		schedule_timeout_interruptible(t);
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_glockd - Reclaim unused glock structures
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One or more of these daemons run, reclaiming glocks on sd_reclaim_list.
+ * Number of daemons can be set by user, with num_glockd mount option.
+ */
+
+int gfs2_glockd(void *data)
+{
+	struct gfs2_sbd *sdp = data;
+
+	while (!kthread_should_stop()) {
+		while (atomic_read(&sdp->sd_reclaim_count))
+			gfs2_reclaim_glock(sdp);
+
+		wait_event_interruptible(sdp->sd_reclaim_wq,
+					 (atomic_read(&sdp->sd_reclaim_count) ||
+					 kthread_should_stop()));
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_recoverd - Recover dead machine's journals
+ * @sdp: Pointer to GFS2 superblock
+ *
+ */
+
+int gfs2_recoverd(void *data)
+{
+	struct gfs2_sbd *sdp = data;
+	unsigned long t;
+
+	while (!kthread_should_stop()) {
+		gfs2_check_journals(sdp);
+		t = gfs2_tune_get(sdp,  gt_recoverd_secs) * HZ;
+		schedule_timeout_interruptible(t);
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * Also, periodically check to make sure that we're using the most recent
+ * journal index.
+ */
+
+int gfs2_logd(void *data)
+{
+	struct gfs2_sbd *sdp = data;
+	struct gfs2_holder ji_gh;
+	unsigned long t;
+
+	while (!kthread_should_stop()) {
+		/* Advance the log tail */
+
+		t = sdp->sd_log_flush_time +
+		    gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
+
+		gfs2_ail1_empty(sdp, DIO_ALL);
+
+		if (time_after_eq(jiffies, t)) {
+			gfs2_log_flush(sdp, NULL);
+			sdp->sd_log_flush_time = jiffies;
+		}
+
+		/* Check for latest journal index */
+
+		t = sdp->sd_jindex_refresh_time +
+		    gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ;
+
+		if (time_after_eq(jiffies, t)) {
+			if (!gfs2_jindex_hold(sdp, &ji_gh))
+				gfs2_glock_dq_uninit(&ji_gh);
+			sdp->sd_jindex_refresh_time = jiffies;
+		}
+
+		t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
+		schedule_timeout_interruptible(t);
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_quotad - Write cached quota changes into the quota file
+ * @sdp: Pointer to GFS2 superblock
+ *
+ */
+
+int gfs2_quotad(void *data)
+{
+	struct gfs2_sbd *sdp = data;
+	unsigned long t;
+	int error;
+
+	while (!kthread_should_stop()) {
+		/* Update the master statfs file */
+
+		t = sdp->sd_statfs_sync_time +
+		    gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;
+
+		if (time_after_eq(jiffies, t)) {
+			error = gfs2_statfs_sync(sdp);
+			if (error &&
+			    error != -EROFS &&
+			    !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+				fs_err(sdp, "quotad: (1) error=%d\n", error);
+			sdp->sd_statfs_sync_time = jiffies;
+		}
+
+		/* Update quota file */
+
+		t = sdp->sd_quota_sync_time +
+		    gfs2_tune_get(sdp, gt_quota_quantum) * HZ;
+
+		if (time_after_eq(jiffies, t)) {
+			error = gfs2_quota_sync(sdp);
+			if (error &&
+			    error != -EROFS &&
+			    !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+				fs_err(sdp, "quotad: (2) error=%d\n", error);
+			sdp->sd_quota_sync_time = jiffies;
+		}
+
+		gfs2_quota_scan(sdp);
+
+		t = gfs2_tune_get(sdp, gt_quotad_secs) * HZ;
+		schedule_timeout_interruptible(t);
+	}
+
+	return 0;
+}
+
diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h
new file mode 100644
index 0000000..80100712
--- /dev/null
+++ b/fs/gfs2/daemon.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __DAEMON_DOT_H__
+#define __DAEMON_DOT_H__
+
+int gfs2_scand(void *data);
+int gfs2_glockd(void *data);
+int gfs2_recoverd(void *data);
+int gfs2_logd(void *data);
+int gfs2_quotad(void *data);
+
+#endif /* __DAEMON_DOT_H__ */
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
new file mode 100644
index 0000000..459498c
--- /dev/null
+++ b/fs/gfs2/dir.c
@@ -0,0 +1,1961 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+/*
+ * Implements Extendible Hashing as described in:
+ *   "Extendible Hashing" by Fagin, et al in
+ *     __ACM Trans. on Database Systems__, Sept 1979.
+ *
+ *
+ * Here's the layout of dirents which is essentially the same as that of ext2
+ * within a single block. The field de_name_len is the number of bytes
+ * actually required for the name (no null terminator). The field de_rec_len
+ * is the number of bytes allocated to the dirent. The offset of the next
+ * dirent in the block is (dirent + dirent->de_rec_len). When a dirent is
+ * deleted, the preceding dirent inherits its allocated space, ie
+ * prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained
+ * by adding de_rec_len to the current dirent, this essentially causes the
+ * deleted dirent to get jumped over when iterating through all the dirents.
+ *
+ * When deleting the first dirent in a block, there is no previous dirent so
+ * the field de_ino is set to zero to designate it as deleted. When allocating
+ * a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the
+ * first dirent has (de_ino == 0) and de_rec_len is large enough, this first
+ * dirent is allocated. Otherwise it must go through all the 'used' dirents
+ * searching for one in which the amount of total space minus the amount of
+ * used space will provide enough space for the new dirent.
+ *
+ * There are two types of blocks in which dirents reside. In a stuffed dinode,
+ * the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of
+ * the block.  In leaves, they begin at offset sizeof(struct gfs2_leaf) from the
+ * beginning of the leaf block. The dirents reside in leaves when
+ *
+ * dip->i_di.di_flags & GFS2_DIF_EXHASH is true
+ *
+ * Otherwise, the dirents are "linear", within a single stuffed dinode block.
+ *
+ * When the dirents are in leaves, the actual contents of the directory file are
+ * used as an array of 64-bit block pointers pointing to the leaf blocks. The
+ * dirents are NOT in the directory file itself. There can be more than one
+ * block pointer in the array that points to the same leaf. In fact, when a
+ * directory is first converted from linear to exhash, all of the pointers
+ * point to the same leaf.
+ *
+ * When a leaf is completely full, the size of the hash table can be
+ * doubled unless it is already at the maximum size which is hard coded into
+ * GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list,
+ * but never before the maximum hash table size has been reached.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/buffer_head.h>
+#include <linux/sort.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/vmalloc.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "dir.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "bmap.h"
+#include "util.h"
+
+#define IS_LEAF     1 /* Hashed (leaf) directory */
+#define IS_DINODE   2 /* Linear (stuffed dinode block) directory */
+
+#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1)
+#define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1))
+
+typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len,
+			    u64 leaf_no, void *data);
+typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent,
+			    const struct qstr *name, void *opaque);
+
+
+int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
+			    struct buffer_head **bhp)
+{
+	struct buffer_head *bh;
+
+	bh = gfs2_meta_new(ip->i_gl, block);
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+	gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
+	gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
+	*bhp = bh;
+	return 0;
+}
+
+static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block,
+					struct buffer_head **bhp)
+{
+	struct buffer_head *bh;
+	int error;
+
+	error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh);
+	if (error)
+		return error;
+	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) {
+		brelse(bh);
+		return -EIO;
+	}
+	*bhp = bh;
+	return 0;
+}
+
+static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
+				  unsigned int offset, unsigned int size)
+{
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		return error;
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
+	if (ip->i_di.di_size < offset + size)
+		ip->i_di.di_size = offset + size;
+	ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+
+	brelse(dibh);
+
+	return size;
+}
+
+
+
+/**
+ * gfs2_dir_write_data - Write directory information to the inode
+ * @ip: The GFS2 inode
+ * @buf: The buffer containing information to be written
+ * @offset: The file offset to start writing at
+ * @size: The amount of data to write
+ *
+ * Returns: The number of bytes correctly written or error code
+ */
+static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
+			       u64 offset, unsigned int size)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head *dibh;
+	u64 lblock, dblock;
+	u32 extlen = 0;
+	unsigned int o;
+	int copied = 0;
+	int error = 0;
+
+	if (!size)
+		return 0;
+
+	if (gfs2_is_stuffed(ip) &&
+	    offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
+		return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset,
+					      size);
+
+	if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
+		return -EINVAL;
+
+	if (gfs2_is_stuffed(ip)) {
+		error = gfs2_unstuff_dinode(ip, NULL);
+		if (error)
+			return error;
+	}
+
+	lblock = offset;
+	o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
+
+	while (copied < size) {
+		unsigned int amount;
+		struct buffer_head *bh;
+		int new;
+
+		amount = size - copied;
+		if (amount > sdp->sd_sb.sb_bsize - o)
+			amount = sdp->sd_sb.sb_bsize - o;
+
+		if (!extlen) {
+			new = 1;
+			error = gfs2_extent_map(&ip->i_inode, lblock, &new,
+						&dblock, &extlen);
+			if (error)
+				goto fail;
+			error = -EIO;
+			if (gfs2_assert_withdraw(sdp, dblock))
+				goto fail;
+		}
+
+		if (amount == sdp->sd_jbsize || new)
+			error = gfs2_dir_get_new_buffer(ip, dblock, &bh);
+		else
+			error = gfs2_dir_get_existing_buffer(ip, dblock, &bh);
+
+		if (error)
+			goto fail;
+
+		gfs2_trans_add_bh(ip->i_gl, bh, 1);
+		memcpy(bh->b_data + o, buf, amount);
+		brelse(bh);
+		if (error)
+			goto fail;
+
+		buf += amount;
+		copied += amount;
+		lblock++;
+		dblock++;
+		extlen--;
+
+		o = sizeof(struct gfs2_meta_header);
+	}
+
+out:
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		return error;
+
+	if (ip->i_di.di_size < offset + copied)
+		ip->i_di.di_size = offset + copied;
+	ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
+
+	return copied;
+fail:
+	if (copied)
+		goto out;
+	return error;
+}
+
+static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
+				 u64 offset, unsigned int size)
+{
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		offset += sizeof(struct gfs2_dinode);
+		memcpy(buf, dibh->b_data + offset, size);
+		brelse(dibh);
+	}
+
+	return (error) ? error : size;
+}
+
+
+/**
+ * gfs2_dir_read_data - Read a data from a directory inode
+ * @ip: The GFS2 Inode
+ * @buf: The buffer to place result into
+ * @offset: File offset to begin jdata_readng from
+ * @size: Amount of data to transfer
+ *
+ * Returns: The amount of data actually copied or the error
+ */
+static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
+			      unsigned int size, unsigned ra)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	u64 lblock, dblock;
+	u32 extlen = 0;
+	unsigned int o;
+	int copied = 0;
+	int error = 0;
+
+	if (offset >= ip->i_di.di_size)
+		return 0;
+
+	if (offset + size > ip->i_di.di_size)
+		size = ip->i_di.di_size - offset;
+
+	if (!size)
+		return 0;
+
+	if (gfs2_is_stuffed(ip))
+		return gfs2_dir_read_stuffed(ip, buf, offset, size);
+
+	if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
+		return -EINVAL;
+
+	lblock = offset;
+	o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
+
+	while (copied < size) {
+		unsigned int amount;
+		struct buffer_head *bh;
+		int new;
+
+		amount = size - copied;
+		if (amount > sdp->sd_sb.sb_bsize - o)
+			amount = sdp->sd_sb.sb_bsize - o;
+
+		if (!extlen) {
+			new = 0;
+			error = gfs2_extent_map(&ip->i_inode, lblock, &new,
+						&dblock, &extlen);
+			if (error || !dblock)
+				goto fail;
+			BUG_ON(extlen < 1);
+			if (!ra)
+				extlen = 1;
+			bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
+		}
+		if (!bh) {
+			error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
+			if (error)
+				goto fail;
+		}
+		error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD);
+		if (error) {
+			brelse(bh);
+			goto fail;
+		}
+		dblock++;
+		extlen--;
+		memcpy(buf, bh->b_data + o, amount);
+		brelse(bh);
+		bh = NULL;
+		buf += amount;
+		copied += amount;
+		lblock++;
+		o = sizeof(struct gfs2_meta_header);
+	}
+
+	return copied;
+fail:
+	return (copied) ? copied : error;
+}
+
+static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent,
+				     const struct qstr *name, int ret)
+{
+	if (dent->de_inum.no_addr != 0 &&
+	    be32_to_cpu(dent->de_hash) == name->hash &&
+	    be16_to_cpu(dent->de_name_len) == name->len &&
+	    memcmp(dent+1, name->name, name->len) == 0)
+		return ret;
+	return 0;
+}
+
+static int gfs2_dirent_find(const struct gfs2_dirent *dent,
+			    const struct qstr *name,
+			    void *opaque)
+{
+	return __gfs2_dirent_find(dent, name, 1);
+}
+
+static int gfs2_dirent_prev(const struct gfs2_dirent *dent,
+			    const struct qstr *name,
+			    void *opaque)
+{
+	return __gfs2_dirent_find(dent, name, 2);
+}
+
+/*
+ * name->name holds ptr to start of block.
+ * name->len holds size of block.
+ */
+static int gfs2_dirent_last(const struct gfs2_dirent *dent,
+			    const struct qstr *name,
+			    void *opaque)
+{
+	const char *start = name->name;
+	const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len);
+	if (name->len == (end - start))
+		return 1;
+	return 0;
+}
+
+static int gfs2_dirent_find_space(const struct gfs2_dirent *dent,
+				  const struct qstr *name,
+				  void *opaque)
+{
+	unsigned required = GFS2_DIRENT_SIZE(name->len);
+	unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
+	unsigned totlen = be16_to_cpu(dent->de_rec_len);
+
+	if (!dent->de_inum.no_addr)
+		actual = GFS2_DIRENT_SIZE(0);
+	if (totlen - actual >= required)
+		return 1;
+	return 0;
+}
+
+struct dirent_gather {
+	const struct gfs2_dirent **pdent;
+	unsigned offset;
+};
+
+static int gfs2_dirent_gather(const struct gfs2_dirent *dent,
+			      const struct qstr *name,
+			      void *opaque)
+{
+	struct dirent_gather *g = opaque;
+	if (dent->de_inum.no_addr) {
+		g->pdent[g->offset++] = dent;
+	}
+	return 0;
+}
+
+/*
+ * Other possible things to check:
+ * - Inode located within filesystem size (and on valid block)
+ * - Valid directory entry type
+ * Not sure how heavy-weight we want to make this... could also check
+ * hash is correct for example, but that would take a lot of extra time.
+ * For now the most important thing is to check that the various sizes
+ * are correct.
+ */
+static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset,
+			     unsigned int size, unsigned int len, int first)
+{
+	const char *msg = "gfs2_dirent too small";
+	if (unlikely(size < sizeof(struct gfs2_dirent)))
+		goto error;
+	msg = "gfs2_dirent misaligned";
+	if (unlikely(offset & 0x7))
+		goto error;
+	msg = "gfs2_dirent points beyond end of block";
+	if (unlikely(offset + size > len))
+		goto error;
+	msg = "zero inode number";
+	if (unlikely(!first && !dent->de_inum.no_addr))
+		goto error;
+	msg = "name length is greater than space in dirent";
+	if (dent->de_inum.no_addr &&
+	    unlikely(sizeof(struct gfs2_dirent)+be16_to_cpu(dent->de_name_len) >
+		     size))
+		goto error;
+	return 0;
+error:
+	printk(KERN_WARNING "gfs2_check_dirent: %s (%s)\n", msg,
+	       first ? "first in block" : "not first in block");
+	return -EIO;
+}
+
+static int gfs2_dirent_offset(const void *buf)
+{
+	const struct gfs2_meta_header *h = buf;
+	int offset;
+
+	BUG_ON(buf == NULL);
+
+	switch(be32_to_cpu(h->mh_type)) {
+	case GFS2_METATYPE_LF:
+		offset = sizeof(struct gfs2_leaf);
+		break;
+	case GFS2_METATYPE_DI:
+		offset = sizeof(struct gfs2_dinode);
+		break;
+	default:
+		goto wrong_type;
+	}
+	return offset;
+wrong_type:
+	printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n",
+	       be32_to_cpu(h->mh_type));
+	return -1;
+}
+
+static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf,
+					    unsigned int len, gfs2_dscan_t scan,
+					    const struct qstr *name,
+					    void *opaque)
+{
+	struct gfs2_dirent *dent, *prev;
+	unsigned offset;
+	unsigned size;
+	int ret = 0;
+
+	ret = gfs2_dirent_offset(buf);
+	if (ret < 0)
+		goto consist_inode;
+
+	offset = ret;
+	prev = NULL;
+	dent = buf + offset;
+	size = be16_to_cpu(dent->de_rec_len);
+	if (gfs2_check_dirent(dent, offset, size, len, 1))
+		goto consist_inode;
+	do {
+		ret = scan(dent, name, opaque);
+		if (ret)
+			break;
+		offset += size;
+		if (offset == len)
+			break;
+		prev = dent;
+		dent = buf + offset;
+		size = be16_to_cpu(dent->de_rec_len);
+		if (gfs2_check_dirent(dent, offset, size, len, 0))
+			goto consist_inode;
+	} while(1);
+
+	switch(ret) {
+	case 0:
+		return NULL;
+	case 1:
+		return dent;
+	case 2:
+		return prev ? prev : dent;
+	default:
+		BUG_ON(ret > 0);
+		return ERR_PTR(ret);
+	}
+
+consist_inode:
+	gfs2_consist_inode(GFS2_I(inode));
+	return ERR_PTR(-EIO);
+}
+
+
+/**
+ * dirent_first - Return the first dirent
+ * @dip: the directory
+ * @bh: The buffer
+ * @dent: Pointer to list of dirents
+ *
+ * return first dirent whether bh points to leaf or stuffed dinode
+ *
+ * Returns: IS_LEAF, IS_DINODE, or -errno
+ */
+
+static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh,
+			struct gfs2_dirent **dent)
+{
+	struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data;
+
+	if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) {
+		if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh))
+			return -EIO;
+		*dent = (struct gfs2_dirent *)(bh->b_data +
+					       sizeof(struct gfs2_leaf));
+		return IS_LEAF;
+	} else {
+		if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI))
+			return -EIO;
+		*dent = (struct gfs2_dirent *)(bh->b_data +
+					       sizeof(struct gfs2_dinode));
+		return IS_DINODE;
+	}
+}
+
+static int dirent_check_reclen(struct gfs2_inode *dip,
+			       const struct gfs2_dirent *d, const void *end_p)
+{
+	const void *ptr = d;
+	u16 rec_len = be16_to_cpu(d->de_rec_len);
+
+	if (unlikely(rec_len < sizeof(struct gfs2_dirent)))
+		goto broken;
+	ptr += rec_len;
+	if (ptr < end_p)
+		return rec_len;
+	if (ptr == end_p)
+		return -ENOENT;
+broken:
+	gfs2_consist_inode(dip);
+	return -EIO;
+}
+
+/**
+ * dirent_next - Next dirent
+ * @dip: the directory
+ * @bh: The buffer
+ * @dent: Pointer to list of dirents
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh,
+		       struct gfs2_dirent **dent)
+{
+	struct gfs2_dirent *cur = *dent, *tmp;
+	char *bh_end = bh->b_data + bh->b_size;
+	int ret;
+
+	ret = dirent_check_reclen(dip, cur, bh_end);
+	if (ret < 0)
+		return ret;
+
+	tmp = (void *)cur + ret;
+	ret = dirent_check_reclen(dip, tmp, bh_end);
+	if (ret == -EIO)
+		return ret;
+
+        /* Only the first dent could ever have de_inum.no_addr == 0 */
+	if (!tmp->de_inum.no_addr) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+
+	*dent = tmp;
+	return 0;
+}
+
+/**
+ * dirent_del - Delete a dirent
+ * @dip: The GFS2 inode
+ * @bh: The buffer
+ * @prev: The previous dirent
+ * @cur: The current dirent
+ *
+ */
+
+static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh,
+		       struct gfs2_dirent *prev, struct gfs2_dirent *cur)
+{
+	u16 cur_rec_len, prev_rec_len;
+
+	if (!cur->de_inum.no_addr) {
+		gfs2_consist_inode(dip);
+		return;
+	}
+
+	gfs2_trans_add_bh(dip->i_gl, bh, 1);
+
+	/* If there is no prev entry, this is the first entry in the block.
+	   The de_rec_len is already as big as it needs to be.  Just zero
+	   out the inode number and return.  */
+
+	if (!prev) {
+		cur->de_inum.no_addr = 0;	/* No endianess worries */
+		return;
+	}
+
+	/*  Combine this dentry with the previous one.  */
+
+	prev_rec_len = be16_to_cpu(prev->de_rec_len);
+	cur_rec_len = be16_to_cpu(cur->de_rec_len);
+
+	if ((char *)prev + prev_rec_len != (char *)cur)
+		gfs2_consist_inode(dip);
+	if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size)
+		gfs2_consist_inode(dip);
+
+	prev_rec_len += cur_rec_len;
+	prev->de_rec_len = cpu_to_be16(prev_rec_len);
+}
+
+/*
+ * Takes a dent from which to grab space as an argument. Returns the
+ * newly created dent.
+ */
+static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode,
+					    struct gfs2_dirent *dent,
+					    const struct qstr *name,
+					    struct buffer_head *bh)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_dirent *ndent;
+	unsigned offset = 0, totlen;
+
+	if (dent->de_inum.no_addr)
+		offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
+	totlen = be16_to_cpu(dent->de_rec_len);
+	BUG_ON(offset + name->len > totlen);
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+	ndent = (struct gfs2_dirent *)((char *)dent + offset);
+	dent->de_rec_len = cpu_to_be16(offset);
+	gfs2_qstr2dirent(name, totlen - offset, ndent);
+	return ndent;
+}
+
+static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode,
+					     struct buffer_head *bh,
+					     const struct qstr *name)
+{
+	struct gfs2_dirent *dent;
+	dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
+				gfs2_dirent_find_space, name, NULL);
+	if (!dent || IS_ERR(dent))
+		return dent;
+	return gfs2_init_dirent(inode, dent, name, bh);
+}
+
+static int get_leaf(struct gfs2_inode *dip, u64 leaf_no,
+		    struct buffer_head **bhp)
+{
+	int error;
+
+	error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp);
+	if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) {
+		/* printk(KERN_INFO "block num=%llu\n", leaf_no); */
+		error = -EIO;
+	}
+
+	return error;
+}
+
+/**
+ * get_leaf_nr - Get a leaf number associated with the index
+ * @dip: The GFS2 inode
+ * @index:
+ * @leaf_out:
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+static int get_leaf_nr(struct gfs2_inode *dip, u32 index,
+		       u64 *leaf_out)
+{
+	u64 leaf_no;
+	int error;
+
+	error = gfs2_dir_read_data(dip, (char *)&leaf_no,
+				    index * sizeof(u64),
+				    sizeof(u64), 0);
+	if (error != sizeof(u64))
+		return (error < 0) ? error : -EIO;
+
+	*leaf_out = be64_to_cpu(leaf_no);
+
+	return 0;
+}
+
+static int get_first_leaf(struct gfs2_inode *dip, u32 index,
+			  struct buffer_head **bh_out)
+{
+	u64 leaf_no;
+	int error;
+
+	error = get_leaf_nr(dip, index, &leaf_no);
+	if (!error)
+		error = get_leaf(dip, leaf_no, bh_out);
+
+	return error;
+}
+
+static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
+					      const struct qstr *name,
+					      gfs2_dscan_t scan,
+					      struct buffer_head **pbh)
+{
+	struct buffer_head *bh;
+	struct gfs2_dirent *dent;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	int error;
+
+	if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
+		struct gfs2_leaf *leaf;
+		unsigned hsize = 1 << ip->i_di.di_depth;
+		unsigned index;
+		u64 ln;
+		if (hsize * sizeof(u64) != ip->i_di.di_size) {
+			gfs2_consist_inode(ip);
+			return ERR_PTR(-EIO);
+		}
+
+		index = name->hash >> (32 - ip->i_di.di_depth);
+		error = get_first_leaf(ip, index, &bh);
+		if (error)
+			return ERR_PTR(error);
+		do {
+			dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
+						scan, name, NULL);
+			if (dent)
+				goto got_dent;
+			leaf = (struct gfs2_leaf *)bh->b_data;
+			ln = be64_to_cpu(leaf->lf_next);
+			brelse(bh);
+			if (!ln)
+				break;
+
+			error = get_leaf(ip, ln, &bh);
+		} while(!error);
+
+		return error ? ERR_PTR(error) : NULL;
+	}
+
+
+	error = gfs2_meta_inode_buffer(ip, &bh);
+	if (error)
+		return ERR_PTR(error);
+	dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL);
+got_dent:
+	if (unlikely(dent == NULL || IS_ERR(dent))) {
+		brelse(bh);
+		bh = NULL;
+	}
+	*pbh = bh;
+	return dent;
+}
+
+static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	u64 bn = gfs2_alloc_meta(ip);
+	struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
+	struct gfs2_leaf *leaf;
+	struct gfs2_dirent *dent;
+	struct qstr name = { .name = "", .len = 0, .hash = 0 };
+	if (!bh)
+		return NULL;
+
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+	gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);
+	leaf = (struct gfs2_leaf *)bh->b_data;
+	leaf->lf_depth = cpu_to_be16(depth);
+	leaf->lf_entries = 0;
+	leaf->lf_dirent_format = cpu_to_be16(GFS2_FORMAT_DE);
+	leaf->lf_next = 0;
+	memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved));
+	dent = (struct gfs2_dirent *)(leaf+1);
+	gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
+	*pbh = bh;
+	return leaf;
+}
+
+/**
+ * dir_make_exhash - Convert a stuffed directory into an ExHash directory
+ * @dip: The GFS2 inode
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+static int dir_make_exhash(struct inode *inode)
+{
+	struct gfs2_inode *dip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct gfs2_dirent *dent;
+	struct qstr args;
+	struct buffer_head *bh, *dibh;
+	struct gfs2_leaf *leaf;
+	int y;
+	u32 x;
+	u64 *lp, bn;
+	int error;
+
+	error = gfs2_meta_inode_buffer(dip, &dibh);
+	if (error)
+		return error;
+
+	/*  Turn over a new leaf  */
+
+	leaf = new_leaf(inode, &bh, 0);
+	if (!leaf)
+		return -ENOSPC;
+	bn = bh->b_blocknr;
+
+	gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16));
+	leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries);
+
+	/*  Copy dirents  */
+
+	gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_leaf), dibh,
+			     sizeof(struct gfs2_dinode));
+
+	/*  Find last entry  */
+
+	x = 0;
+	args.len = bh->b_size - sizeof(struct gfs2_dinode) +
+		   sizeof(struct gfs2_leaf);
+	args.name = bh->b_data;
+	dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size,
+				gfs2_dirent_last, &args, NULL);
+	if (!dent) {
+		brelse(bh);
+		brelse(dibh);
+		return -EIO;
+	}
+	if (IS_ERR(dent)) {
+		brelse(bh);
+		brelse(dibh);
+		return PTR_ERR(dent);
+	}
+
+	/*  Adjust the last dirent's record length
+	   (Remember that dent still points to the last entry.)  */
+
+	dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) +
+		sizeof(struct gfs2_dinode) -
+		sizeof(struct gfs2_leaf));
+
+	brelse(bh);
+
+	/*  We're done with the new leaf block, now setup the new
+	    hash table.  */
+
+	gfs2_trans_add_bh(dip->i_gl, dibh, 1);
+	gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+
+	lp = (u64 *)(dibh->b_data + sizeof(struct gfs2_dinode));
+
+	for (x = sdp->sd_hash_ptrs; x--; lp++)
+		*lp = cpu_to_be64(bn);
+
+	dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2;
+	dip->i_di.di_blocks++;
+	dip->i_di.di_flags |= GFS2_DIF_EXHASH;
+	dip->i_di.di_payload_format = 0;
+
+	for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
+	dip->i_di.di_depth = y;
+
+	gfs2_dinode_out(&dip->i_di, dibh->b_data);
+
+	brelse(dibh);
+
+	return 0;
+}
+
+/**
+ * dir_split_leaf - Split a leaf block into two
+ * @dip: The GFS2 inode
+ * @index:
+ * @leaf_no:
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+static int dir_split_leaf(struct inode *inode, const struct qstr *name)
+{
+	struct gfs2_inode *dip = GFS2_I(inode);
+	struct buffer_head *nbh, *obh, *dibh;
+	struct gfs2_leaf *nleaf, *oleaf;
+	struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new;
+	u32 start, len, half_len, divider;
+	u64 bn, *lp, leaf_no;
+	u32 index;
+	int x, moved = 0;
+	int error;
+
+	index = name->hash >> (32 - dip->i_di.di_depth);
+	error = get_leaf_nr(dip, index, &leaf_no);
+	if (error)
+		return error;
+
+	/*  Get the old leaf block  */
+	error = get_leaf(dip, leaf_no, &obh);
+	if (error)
+		return error;
+
+	oleaf = (struct gfs2_leaf *)obh->b_data;
+	if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) {
+		brelse(obh);
+		return 1; /* can't split */
+	}
+
+	gfs2_trans_add_bh(dip->i_gl, obh, 1);
+
+	nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1);
+	if (!nleaf) {
+		brelse(obh);
+		return -ENOSPC;
+	}
+	bn = nbh->b_blocknr;
+
+	/*  Compute the start and len of leaf pointers in the hash table.  */
+	len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth));
+	half_len = len >> 1;
+	if (!half_len) {
+		printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index);
+		gfs2_consist_inode(dip);
+		error = -EIO;
+		goto fail_brelse;
+	}
+
+	start = (index & ~(len - 1));
+
+	/* Change the pointers.
+	   Don't bother distinguishing stuffed from non-stuffed.
+	   This code is complicated enough already. */
+	lp = kmalloc(half_len * sizeof(u64), GFP_NOFS | __GFP_NOFAIL);
+	/*  Change the pointers  */
+	for (x = 0; x < half_len; x++)
+		lp[x] = cpu_to_be64(bn);
+
+	error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64),
+				    half_len * sizeof(u64));
+	if (error != half_len * sizeof(u64)) {
+		if (error >= 0)
+			error = -EIO;
+		goto fail_lpfree;
+	}
+
+	kfree(lp);
+
+	/*  Compute the divider  */
+	divider = (start + half_len) << (32 - dip->i_di.di_depth);
+
+	/*  Copy the entries  */
+	dirent_first(dip, obh, &dent);
+
+	do {
+		next = dent;
+		if (dirent_next(dip, obh, &next))
+			next = NULL;
+
+		if (dent->de_inum.no_addr &&
+		    be32_to_cpu(dent->de_hash) < divider) {
+			struct qstr str;
+			str.name = (char*)(dent+1);
+			str.len = be16_to_cpu(dent->de_name_len);
+			str.hash = be32_to_cpu(dent->de_hash);
+			new = gfs2_dirent_alloc(inode, nbh, &str);
+			if (IS_ERR(new)) {
+				error = PTR_ERR(new);
+				break;
+			}
+
+			new->de_inum = dent->de_inum; /* No endian worries */
+			new->de_type = dent->de_type; /* No endian worries */
+			nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1);
+
+			dirent_del(dip, obh, prev, dent);
+
+			if (!oleaf->lf_entries)
+				gfs2_consist_inode(dip);
+			oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1);
+
+			if (!prev)
+				prev = dent;
+
+			moved = 1;
+		} else {
+			prev = dent;
+		}
+		dent = next;
+	} while (dent);
+
+	oleaf->lf_depth = nleaf->lf_depth;
+
+	error = gfs2_meta_inode_buffer(dip, &dibh);
+	if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
+		dip->i_di.di_blocks++;
+		gfs2_dinode_out(&dip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	brelse(obh);
+	brelse(nbh);
+
+	return error;
+
+fail_lpfree:
+	kfree(lp);
+
+fail_brelse:
+	brelse(obh);
+	brelse(nbh);
+	return error;
+}
+
+/**
+ * dir_double_exhash - Double size of ExHash table
+ * @dip: The GFS2 dinode
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+static int dir_double_exhash(struct gfs2_inode *dip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct buffer_head *dibh;
+	u32 hsize;
+	u64 *buf;
+	u64 *from, *to;
+	u64 block;
+	int x;
+	int error = 0;
+
+	hsize = 1 << dip->i_di.di_depth;
+	if (hsize * sizeof(u64) != dip->i_di.di_size) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+
+	/*  Allocate both the "from" and "to" buffers in one big chunk  */
+
+	buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL);
+
+	for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {
+		error = gfs2_dir_read_data(dip, (char *)buf,
+					    block * sdp->sd_hash_bsize,
+					    sdp->sd_hash_bsize, 1);
+		if (error != sdp->sd_hash_bsize) {
+			if (error >= 0)
+				error = -EIO;
+			goto fail;
+		}
+
+		from = buf;
+		to = (u64 *)((char *)buf + sdp->sd_hash_bsize);
+
+		for (x = sdp->sd_hash_ptrs; x--; from++) {
+			*to++ = *from;	/*  No endianess worries  */
+			*to++ = *from;
+		}
+
+		error = gfs2_dir_write_data(dip,
+					     (char *)buf + sdp->sd_hash_bsize,
+					     block * sdp->sd_sb.sb_bsize,
+					     sdp->sd_sb.sb_bsize);
+		if (error != sdp->sd_sb.sb_bsize) {
+			if (error >= 0)
+				error = -EIO;
+			goto fail;
+		}
+	}
+
+	kfree(buf);
+
+	error = gfs2_meta_inode_buffer(dip, &dibh);
+	if (!gfs2_assert_withdraw(sdp, !error)) {
+		dip->i_di.di_depth++;
+		gfs2_dinode_out(&dip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	return error;
+
+fail:
+	kfree(buf);
+	return error;
+}
+
+/**
+ * compare_dents - compare directory entries by hash value
+ * @a: first dent
+ * @b: second dent
+ *
+ * When comparing the hash entries of @a to @b:
+ *   gt: returns 1
+ *   lt: returns -1
+ *   eq: returns 0
+ */
+
+static int compare_dents(const void *a, const void *b)
+{
+	const struct gfs2_dirent *dent_a, *dent_b;
+	u32 hash_a, hash_b;
+	int ret = 0;
+
+	dent_a = *(const struct gfs2_dirent **)a;
+	hash_a = be32_to_cpu(dent_a->de_hash);
+
+	dent_b = *(const struct gfs2_dirent **)b;
+	hash_b = be32_to_cpu(dent_b->de_hash);
+
+	if (hash_a > hash_b)
+		ret = 1;
+	else if (hash_a < hash_b)
+		ret = -1;
+	else {
+		unsigned int len_a = be16_to_cpu(dent_a->de_name_len);
+		unsigned int len_b = be16_to_cpu(dent_b->de_name_len);
+
+		if (len_a > len_b)
+			ret = 1;
+		else if (len_a < len_b)
+			ret = -1;
+		else
+			ret = memcmp(dent_a + 1, dent_b + 1, len_a);
+	}
+
+	return ret;
+}
+
+/**
+ * do_filldir_main - read out directory entries
+ * @dip: The GFS2 inode
+ * @offset: The offset in the file to read from
+ * @opaque: opaque data to pass to filldir
+ * @filldir: The function to pass entries to
+ * @darr: an array of struct gfs2_dirent pointers to read
+ * @entries: the number of entries in darr
+ * @copied: pointer to int that's non-zero if a entry has been copied out
+ *
+ * Jump through some hoops to make sure that if there are hash collsions,
+ * they are read out at the beginning of a buffer.  We want to minimize
+ * the possibility that they will fall into different readdir buffers or
+ * that someone will want to seek to that location.
+ *
+ * Returns: errno, >0 on exception from filldir
+ */
+
+static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
+			   void *opaque, gfs2_filldir_t filldir,
+			   const struct gfs2_dirent **darr, u32 entries,
+			   int *copied)
+{
+	const struct gfs2_dirent *dent, *dent_next;
+	struct gfs2_inum inum;
+	u64 off, off_next;
+	unsigned int x, y;
+	int run = 0;
+	int error = 0;
+
+	sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL);
+
+	dent_next = darr[0];
+	off_next = be32_to_cpu(dent_next->de_hash);
+	off_next = gfs2_disk_hash2offset(off_next);
+
+	for (x = 0, y = 1; x < entries; x++, y++) {
+		dent = dent_next;
+		off = off_next;
+
+		if (y < entries) {
+			dent_next = darr[y];
+			off_next = be32_to_cpu(dent_next->de_hash);
+			off_next = gfs2_disk_hash2offset(off_next);
+
+			if (off < *offset)
+				continue;
+			*offset = off;
+
+			if (off_next == off) {
+				if (*copied && !run)
+					return 1;
+				run = 1;
+			} else
+				run = 0;
+		} else {
+			if (off < *offset)
+				continue;
+			*offset = off;
+		}
+
+		gfs2_inum_in(&inum, (char *)&dent->de_inum);
+
+		error = filldir(opaque, (const char *)(dent + 1),
+				be16_to_cpu(dent->de_name_len),
+				off, &inum,
+				be16_to_cpu(dent->de_type));
+		if (error)
+			return 1;
+
+		*copied = 1;
+	}
+
+	/* Increment the *offset by one, so the next time we come into the
+	   do_filldir fxn, we get the next entry instead of the last one in the
+	   current leaf */
+
+	(*offset)++;
+
+	return 0;
+}
+
+static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
+			      gfs2_filldir_t filldir, int *copied,
+			      unsigned *depth, u64 leaf_no)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct buffer_head *bh;
+	struct gfs2_leaf *lf;
+	unsigned entries = 0;
+	unsigned leaves = 0;
+	const struct gfs2_dirent **darr, *dent;
+	struct dirent_gather g;
+	struct buffer_head **larr;
+	int leaf = 0;
+	int error, i;
+	u64 lfn = leaf_no;
+
+	do {
+		error = get_leaf(ip, lfn, &bh);
+		if (error)
+			goto out;
+		lf = (struct gfs2_leaf *)bh->b_data;
+		if (leaves == 0)
+			*depth = be16_to_cpu(lf->lf_depth);
+		entries += be16_to_cpu(lf->lf_entries);
+		leaves++;
+		lfn = be64_to_cpu(lf->lf_next);
+		brelse(bh);
+	} while(lfn);
+
+	if (!entries)
+		return 0;
+
+	error = -ENOMEM;
+	larr = vmalloc((leaves + entries) * sizeof(void *));
+	if (!larr)
+		goto out;
+	darr = (const struct gfs2_dirent **)(larr + leaves);
+	g.pdent = darr;
+	g.offset = 0;
+	lfn = leaf_no;
+
+	do {
+		error = get_leaf(ip, lfn, &bh);
+		if (error)
+			goto out_kfree;
+		lf = (struct gfs2_leaf *)bh->b_data;
+		lfn = be64_to_cpu(lf->lf_next);
+		if (lf->lf_entries) {
+			dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
+						gfs2_dirent_gather, NULL, &g);
+			error = PTR_ERR(dent);
+			if (IS_ERR(dent)) {
+				goto out_kfree;
+			}
+			error = 0;
+			larr[leaf++] = bh;
+		} else {
+			brelse(bh);
+		}
+	} while(lfn);
+
+	error = do_filldir_main(ip, offset, opaque, filldir, darr,
+				entries, copied);
+out_kfree:
+	for(i = 0; i < leaf; i++)
+		brelse(larr[i]);
+	vfree(larr);
+out:
+	return error;
+}
+
+/**
+ * dir_e_read - Reads the entries from a directory into a filldir buffer
+ * @dip: dinode pointer
+ * @offset: the hash of the last entry read shifted to the right once
+ * @opaque: buffer for the filldir function to fill
+ * @filldir: points to the filldir function to use
+ *
+ * Returns: errno
+ */
+
+static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
+		      gfs2_filldir_t filldir)
+{
+	struct gfs2_inode *dip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	u32 hsize, len = 0;
+	u32 ht_offset, lp_offset, ht_offset_cur = -1;
+	u32 hash, index;
+	u64 *lp;
+	int copied = 0;
+	int error = 0;
+	unsigned depth = 0;
+
+	hsize = 1 << dip->i_di.di_depth;
+	if (hsize * sizeof(u64) != dip->i_di.di_size) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+
+	hash = gfs2_dir_offset2hash(*offset);
+	index = hash >> (32 - dip->i_di.di_depth);
+
+	lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL);
+	if (!lp)
+		return -ENOMEM;
+
+	while (index < hsize) {
+		lp_offset = index & (sdp->sd_hash_ptrs - 1);
+		ht_offset = index - lp_offset;
+
+		if (ht_offset_cur != ht_offset) {
+			error = gfs2_dir_read_data(dip, (char *)lp,
+						ht_offset * sizeof(u64),
+						sdp->sd_hash_bsize, 1);
+			if (error != sdp->sd_hash_bsize) {
+				if (error >= 0)
+					error = -EIO;
+				goto out;
+			}
+			ht_offset_cur = ht_offset;
+		}
+
+		error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
+					   &copied, &depth,
+					   be64_to_cpu(lp[lp_offset]));
+		if (error)
+			break;
+
+		len = 1 << (dip->i_di.di_depth - depth);
+		index = (index & ~(len - 1)) + len;
+	}
+
+out:
+	kfree(lp);
+	if (error > 0)
+		error = 0;
+	return error;
+}
+
+int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
+		  gfs2_filldir_t filldir)
+{
+	struct gfs2_inode *dip = GFS2_I(inode);
+	struct dirent_gather g;
+	const struct gfs2_dirent **darr, *dent;
+	struct buffer_head *dibh;
+	int copied = 0;
+	int error;
+
+	if (!dip->i_di.di_entries)
+		return 0;
+
+	if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
+		return dir_e_read(inode, offset, opaque, filldir);
+
+	if (!gfs2_is_stuffed(dip)) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+
+	error = gfs2_meta_inode_buffer(dip, &dibh);
+	if (error)
+		return error;
+
+	error = -ENOMEM;
+	darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
+		       GFP_KERNEL);
+	if (darr) {
+		g.pdent = darr;
+		g.offset = 0;
+		dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size,
+					gfs2_dirent_gather, NULL, &g);
+		if (IS_ERR(dent)) {
+			error = PTR_ERR(dent);
+			goto out;
+		}
+		error = do_filldir_main(dip, offset, opaque, filldir, darr,
+					dip->i_di.di_entries, &copied);
+out:
+		kfree(darr);
+	}
+
+	if (error > 0)
+		error = 0;
+
+	brelse(dibh);
+
+	return error;
+}
+
+/**
+ * gfs2_dir_search - Search a directory
+ * @dip: The GFS2 inode
+ * @filename:
+ * @inode:
+ *
+ * This routine searches a directory for a file or another directory.
+ * Assumes a glock is held on dip.
+ *
+ * Returns: errno
+ */
+
+int gfs2_dir_search(struct inode *dir, const struct qstr *name,
+		    struct gfs2_inum *inum, unsigned int *type)
+{
+	struct buffer_head *bh;
+	struct gfs2_dirent *dent;
+
+	dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
+	if (dent) {
+		if (IS_ERR(dent))
+			return PTR_ERR(dent);
+		if (inum)
+			gfs2_inum_in(inum, (char *)&dent->de_inum);
+		if (type)
+			*type = be16_to_cpu(dent->de_type);
+		brelse(bh);
+		return 0;
+	}
+	return -ENOENT;
+}
+
+static int dir_new_leaf(struct inode *inode, const struct qstr *name)
+{
+	struct buffer_head *bh, *obh;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_leaf *leaf, *oleaf;
+	int error;
+	u32 index;
+	u64 bn;
+
+	index = name->hash >> (32 - ip->i_di.di_depth);
+	error = get_first_leaf(ip, index, &obh);
+	if (error)
+		return error;
+	do {
+		oleaf = (struct gfs2_leaf *)obh->b_data;
+		bn = be64_to_cpu(oleaf->lf_next);
+		if (!bn)
+			break;
+		brelse(obh);
+		error = get_leaf(ip, bn, &obh);
+		if (error)
+			return error;
+	} while(1);
+
+	gfs2_trans_add_bh(ip->i_gl, obh, 1);
+
+	leaf = new_leaf(inode, &bh, be16_to_cpu(oleaf->lf_depth));
+	if (!leaf) {
+		brelse(obh);
+		return -ENOSPC;
+	}
+	oleaf->lf_next = cpu_to_be64(bh->b_blocknr);
+	brelse(bh);
+	brelse(obh);
+
+	error = gfs2_meta_inode_buffer(ip, &bh);
+	if (error)
+		return error;
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+	ip->i_di.di_blocks++;
+	gfs2_dinode_out(&ip->i_di, bh->b_data);
+	brelse(bh);
+	return 0;
+}
+
+/**
+ * gfs2_dir_add - Add new filename into directory
+ * @dip: The GFS2 inode
+ * @filename: The new name
+ * @inode: The inode number of the entry
+ * @type: The type of the entry
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+int gfs2_dir_add(struct inode *inode, const struct qstr *name,
+		 const struct gfs2_inum *inum, unsigned type)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct buffer_head *bh;
+	struct gfs2_dirent *dent;
+	struct gfs2_leaf *leaf;
+	int error;
+
+	while(1) {
+		dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space,
+					  &bh);
+		if (dent) {
+			if (IS_ERR(dent))
+				return PTR_ERR(dent);
+			dent = gfs2_init_dirent(inode, dent, name, bh);
+			gfs2_inum_out(inum, (char *)&dent->de_inum);
+			dent->de_type = cpu_to_be16(type);
+			if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
+				leaf = (struct gfs2_leaf *)bh->b_data;
+				leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1);
+			}
+			brelse(bh);
+			error = gfs2_meta_inode_buffer(ip, &bh);
+			if (error)
+				break;
+			gfs2_trans_add_bh(ip->i_gl, bh, 1);
+			ip->i_di.di_entries++;
+			ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+			gfs2_dinode_out(&ip->i_di, bh->b_data);
+			brelse(bh);
+			error = 0;
+			break;
+		}
+		if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
+			error = dir_make_exhash(inode);
+			if (error)
+				break;
+			continue;
+		}
+		error = dir_split_leaf(inode, name);
+		if (error == 0)
+			continue;
+		if (error < 0)
+			break;
+		if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) {
+			error = dir_double_exhash(ip);
+			if (error)
+				break;
+			error = dir_split_leaf(inode, name);
+			if (error < 0)
+				break;
+			if (error == 0)
+				continue;
+		}
+		error = dir_new_leaf(inode, name);
+		if (!error)
+			continue;
+		error = -ENOSPC;
+		break;
+	}
+	return error;
+}
+
+
+/**
+ * gfs2_dir_del - Delete a directory entry
+ * @dip: The GFS2 inode
+ * @filename: The filename
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name)
+{
+	struct gfs2_dirent *dent, *prev = NULL;
+	struct buffer_head *bh;
+	int error;
+
+	/* Returns _either_ the entry (if its first in block) or the
+	   previous entry otherwise */
+	dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh);
+	if (!dent) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+	if (IS_ERR(dent)) {
+		gfs2_consist_inode(dip);
+		return PTR_ERR(dent);
+	}
+	/* If not first in block, adjust pointers accordingly */
+	if (gfs2_dirent_find(dent, name, NULL) == 0) {
+		prev = dent;
+		dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len));
+	}
+
+	dirent_del(dip, bh, prev, dent);
+	if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
+		struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
+		u16 entries = be16_to_cpu(leaf->lf_entries);
+		if (!entries)
+			gfs2_consist_inode(dip);
+		leaf->lf_entries = cpu_to_be16(--entries);
+	}
+	brelse(bh);
+
+	error = gfs2_meta_inode_buffer(dip, &bh);
+	if (error)
+		return error;
+
+	if (!dip->i_di.di_entries)
+		gfs2_consist_inode(dip);
+	gfs2_trans_add_bh(dip->i_gl, bh, 1);
+	dip->i_di.di_entries--;
+	dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds();
+	gfs2_dinode_out(&dip->i_di, bh->b_data);
+	brelse(bh);
+	mark_inode_dirty(&dip->i_inode);
+
+	return error;
+}
+
+/**
+ * gfs2_dir_mvino - Change inode number of directory entry
+ * @dip: The GFS2 inode
+ * @filename:
+ * @new_inode:
+ *
+ * This routine changes the inode number of a directory entry.  It's used
+ * by rename to change ".." when a directory is moved.
+ * Assumes a glock is held on dvp.
+ *
+ * Returns: errno
+ */
+
+int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
+		   struct gfs2_inum *inum, unsigned int new_type)
+{
+	struct buffer_head *bh;
+	struct gfs2_dirent *dent;
+	int error;
+
+	dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh);
+	if (!dent) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+
+	gfs2_trans_add_bh(dip->i_gl, bh, 1);
+	gfs2_inum_out(inum, (char *)&dent->de_inum);
+	dent->de_type = cpu_to_be16(new_type);
+
+	if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
+		brelse(bh);
+		error = gfs2_meta_inode_buffer(dip, &bh);
+		if (error)
+			return error;
+		gfs2_trans_add_bh(dip->i_gl, bh, 1);
+	}
+
+	dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds();
+	gfs2_dinode_out(&dip->i_di, bh->b_data);
+	brelse(bh);
+	return 0;
+}
+
+/**
+ * foreach_leaf - call a function for each leaf in a directory
+ * @dip: the directory
+ * @lc: the function to call for each each
+ * @data: private data to pass to it
+ *
+ * Returns: errno
+ */
+
+static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct buffer_head *bh;
+	struct gfs2_leaf *leaf;
+	u32 hsize, len;
+	u32 ht_offset, lp_offset, ht_offset_cur = -1;
+	u32 index = 0;
+	u64 *lp;
+	u64 leaf_no;
+	int error = 0;
+
+	hsize = 1 << dip->i_di.di_depth;
+	if (hsize * sizeof(u64) != dip->i_di.di_size) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+
+	lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL);
+	if (!lp)
+		return -ENOMEM;
+
+	while (index < hsize) {
+		lp_offset = index & (sdp->sd_hash_ptrs - 1);
+		ht_offset = index - lp_offset;
+
+		if (ht_offset_cur != ht_offset) {
+			error = gfs2_dir_read_data(dip, (char *)lp,
+						ht_offset * sizeof(u64),
+						sdp->sd_hash_bsize, 1);
+			if (error != sdp->sd_hash_bsize) {
+				if (error >= 0)
+					error = -EIO;
+				goto out;
+			}
+			ht_offset_cur = ht_offset;
+		}
+
+		leaf_no = be64_to_cpu(lp[lp_offset]);
+		if (leaf_no) {
+			error = get_leaf(dip, leaf_no, &bh);
+			if (error)
+				goto out;
+			leaf = (struct gfs2_leaf *)bh->b_data;
+			len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth));
+			brelse(bh);
+
+			error = lc(dip, index, len, leaf_no, data);
+			if (error)
+				goto out;
+
+			index = (index & ~(len - 1)) + len;
+		} else
+			index++;
+	}
+
+	if (index != hsize) {
+		gfs2_consist_inode(dip);
+		error = -EIO;
+	}
+
+out:
+	kfree(lp);
+
+	return error;
+}
+
+/**
+ * leaf_dealloc - Deallocate a directory leaf
+ * @dip: the directory
+ * @index: the hash table offset in the directory
+ * @len: the number of pointers to this leaf
+ * @leaf_no: the leaf number
+ * @data: not used
+ *
+ * Returns: errno
+ */
+
+static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
+			u64 leaf_no, void *data)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct gfs2_leaf *tmp_leaf;
+	struct gfs2_rgrp_list rlist;
+	struct buffer_head *bh, *dibh;
+	u64 blk, nblk;
+	unsigned int rg_blocks = 0, l_blocks = 0;
+	char *ht;
+	unsigned int x, size = len * sizeof(u64);
+	int error;
+
+	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
+
+	ht = kzalloc(size, GFP_KERNEL);
+	if (!ht)
+		return -ENOMEM;
+
+	gfs2_alloc_get(dip);
+
+	error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out;
+
+	error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh);
+	if (error)
+		goto out_qs;
+
+	/*  Count the number of leaves  */
+
+	for (blk = leaf_no; blk; blk = nblk) {
+		error = get_leaf(dip, blk, &bh);
+		if (error)
+			goto out_rlist;
+		tmp_leaf = (struct gfs2_leaf *)bh->b_data;
+		nblk = be64_to_cpu(tmp_leaf->lf_next);
+		brelse(bh);
+
+		gfs2_rlist_add(sdp, &rlist, blk);
+		l_blocks++;
+	}
+
+	gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
+
+	for (x = 0; x < rlist.rl_rgrps; x++) {
+		struct gfs2_rgrpd *rgd;
+		rgd = rlist.rl_ghs[x].gh_gl->gl_object;
+		rg_blocks += rgd->rd_ri.ri_length;
+	}
+
+	error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
+	if (error)
+		goto out_rlist;
+
+	error = gfs2_trans_begin(sdp,
+			rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) +
+			RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks);
+	if (error)
+		goto out_rg_gunlock;
+
+	for (blk = leaf_no; blk; blk = nblk) {
+		error = get_leaf(dip, blk, &bh);
+		if (error)
+			goto out_end_trans;
+		tmp_leaf = (struct gfs2_leaf *)bh->b_data;
+		nblk = be64_to_cpu(tmp_leaf->lf_next);
+		brelse(bh);
+
+		gfs2_free_meta(dip, blk, 1);
+
+		if (!dip->i_di.di_blocks)
+			gfs2_consist_inode(dip);
+		dip->i_di.di_blocks--;
+	}
+
+	error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size);
+	if (error != size) {
+		if (error >= 0)
+			error = -EIO;
+		goto out_end_trans;
+	}
+
+	error = gfs2_meta_inode_buffer(dip, &dibh);
+	if (error)
+		goto out_end_trans;
+
+	gfs2_trans_add_bh(dip->i_gl, dibh, 1);
+	gfs2_dinode_out(&dip->i_di, dibh->b_data);
+	brelse(dibh);
+
+out_end_trans:
+	gfs2_trans_end(sdp);
+out_rg_gunlock:
+	gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
+out_rlist:
+	gfs2_rlist_free(&rlist);
+	gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh);
+out_qs:
+	gfs2_quota_unhold(dip);
+out:
+	gfs2_alloc_put(dip);
+	kfree(ht);
+	return error;
+}
+
+/**
+ * gfs2_dir_exhash_dealloc - free all the leaf blocks in a directory
+ * @dip: the directory
+ *
+ * Dealloc all on-disk directory leaves to FREEMETA state
+ * Change on-disk inode type to "regular file"
+ *
+ * Returns: errno
+ */
+
+int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct buffer_head *bh;
+	int error;
+
+	/* Dealloc on-disk leaves to FREEMETA state */
+	error = foreach_leaf(dip, leaf_dealloc, NULL);
+	if (error)
+		return error;
+
+	/* Make this a regular file in case we crash.
+	   (We don't want to free these blocks a second time.)  */
+
+	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+	if (error)
+		return error;
+
+	error = gfs2_meta_inode_buffer(dip, &bh);
+	if (!error) {
+		gfs2_trans_add_bh(dip->i_gl, bh, 1);
+		((struct gfs2_dinode *)bh->b_data)->di_mode =
+						cpu_to_be32(S_IFREG);
+		brelse(bh);
+	}
+
+	gfs2_trans_end(sdp);
+
+	return error;
+}
+
+/**
+ * gfs2_diradd_alloc_required - find if adding entry will require an allocation
+ * @ip: the file being written to
+ * @filname: the filename that's going to be added
+ *
+ * Returns: 1 if alloc required, 0 if not, -ve on error
+ */
+
+int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name)
+{
+	struct gfs2_dirent *dent;
+	struct buffer_head *bh;
+
+	dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh);
+	if (!dent) {
+		return 1;
+	}
+	if (IS_ERR(dent))
+		return PTR_ERR(dent);
+	brelse(bh);
+	return 0;
+}
+
diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
new file mode 100644
index 0000000..3712334
--- /dev/null
+++ b/fs/gfs2/dir.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __DIR_DOT_H__
+#define __DIR_DOT_H__
+
+#include <linux/dcache.h>
+
+struct inode;
+struct gfs2_inode;
+struct gfs2_inum;
+
+/**
+ * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read()
+ * @opaque: opaque data used by the function
+ * @name: the name of the directory entry
+ * @length: the length of the name
+ * @offset: the entry's offset in the directory
+ * @inum: the inode number the entry points to
+ * @type: the type of inode the entry points to
+ *
+ * Returns: 0 on success, 1 if buffer full
+ */
+
+typedef int (*gfs2_filldir_t) (void *opaque,
+			      const char *name, unsigned int length,
+			      u64 offset,
+			      struct gfs2_inum *inum, unsigned int type);
+
+int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
+		    struct gfs2_inum *inum, unsigned int *type);
+int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
+		 const struct gfs2_inum *inum, unsigned int type);
+int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
+int gfs2_dir_read(struct inode *inode, u64 * offset, void *opaque,
+		  gfs2_filldir_t filldir);
+int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
+		   struct gfs2_inum *new_inum, unsigned int new_type);
+
+int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
+
+int gfs2_diradd_alloc_required(struct inode *dir,
+			       const struct qstr *filename);
+int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
+			    struct buffer_head **bhp);
+
+static inline u32 gfs2_disk_hash(const char *data, int len)
+{
+        return crc32_le((u32)~0, data, len) ^ (u32)~0;
+}
+
+
+static inline void gfs2_str2qstr(struct qstr *name, const char *fname)
+{
+	name->name = fname;
+	name->len = strlen(fname);
+	name->hash = gfs2_disk_hash(name->name, name->len);
+}
+
+/* N.B. This probably ought to take inum & type as args as well */
+static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct gfs2_dirent *dent)
+{
+	dent->de_inum.no_addr = cpu_to_be64(0);
+	dent->de_inum.no_formal_ino = cpu_to_be64(0);
+	dent->de_hash = cpu_to_be32(name->hash);
+	dent->de_rec_len = cpu_to_be16(reclen);
+	dent->de_name_len = cpu_to_be16(name->len);
+	dent->de_type = cpu_to_be16(0);
+	memset(dent->__pad, 0, sizeof(dent->__pad));
+	memcpy(dent + 1, name->name, name->len);
+}
+
+#endif /* __DIR_DOT_H__ */
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
new file mode 100644
index 0000000..92c54e9
--- /dev/null
+++ b/fs/gfs2/eaops.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/xattr.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "util.h"
+
+/**
+ * gfs2_ea_name2type - get the type of the ea, and truncate type from the name
+ * @namep: ea name, possibly with type appended
+ *
+ * Returns: GFS2_EATYPE_XXX
+ */
+
+unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
+{
+	unsigned int type;
+
+	if (strncmp(name, "system.", 7) == 0) {
+		type = GFS2_EATYPE_SYS;
+		if (truncated_name)
+			*truncated_name = name + sizeof("system.") - 1;
+	} else if (strncmp(name, "user.", 5) == 0) {
+		type = GFS2_EATYPE_USR;
+		if (truncated_name)
+			*truncated_name = name + sizeof("user.") - 1;
+	} else if (strncmp(name, "security.", 9) == 0) {
+		type = GFS2_EATYPE_SECURITY;
+		if (truncated_name)
+			*truncated_name = name + sizeof("security.") - 1;
+	} else {
+		type = GFS2_EATYPE_UNUSED;
+		if (truncated_name)
+			*truncated_name = NULL;
+	}
+
+	return type;
+}
+
+static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct inode *inode = &ip->i_inode;
+	int error = permission(inode, MAY_READ, NULL);
+	if (error)
+		return error;
+
+	return gfs2_ea_get_i(ip, er);
+}
+
+static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct inode *inode = &ip->i_inode;
+
+	if (S_ISREG(inode->i_mode) ||
+	    (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
+		int error = permission(inode, MAY_WRITE, NULL);
+		if (error)
+			return error;
+	} else
+		return -EPERM;
+
+	return gfs2_ea_set_i(ip, er);
+}
+
+static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct inode *inode = &ip->i_inode;
+
+	if (S_ISREG(inode->i_mode) ||
+	    (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
+		int error = permission(inode, MAY_WRITE, NULL);
+		if (error)
+			return error;
+	} else
+		return -EPERM;
+
+	return gfs2_ea_remove_i(ip, er);
+}
+
+static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
+	    !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
+	    !capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 &&
+	    (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
+	     GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
+		return -EOPNOTSUPP;
+
+
+
+	return gfs2_ea_get_i(ip, er);
+}
+
+static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	int remove = 0;
+	int error;
+
+	if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
+		if (!(er->er_flags & GFS2_ERF_MODE)) {
+			er->er_mode = ip->i_di.di_mode;
+			er->er_flags |= GFS2_ERF_MODE;
+		}
+		error = gfs2_acl_validate_set(ip, 1, er,
+					      &remove, &er->er_mode);
+		if (error)
+			return error;
+		error = gfs2_ea_set_i(ip, er);
+		if (error)
+			return error;
+		if (remove)
+			gfs2_ea_remove_i(ip, er);
+		return 0;
+
+	} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
+		error = gfs2_acl_validate_set(ip, 0, er,
+					      &remove, NULL);
+		if (error)
+			return error;
+		if (!remove)
+			error = gfs2_ea_set_i(ip, er);
+		else {
+			error = gfs2_ea_remove_i(ip, er);
+			if (error == -ENODATA)
+				error = 0;
+		}
+		return error;
+	}
+
+	return -EPERM;
+}
+
+static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
+		int error = gfs2_acl_validate_remove(ip, 1);
+		if (error)
+			return error;
+
+	} else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
+		int error = gfs2_acl_validate_remove(ip, 0);
+		if (error)
+			return error;
+
+	} else
+		return -EPERM;
+
+	return gfs2_ea_remove_i(ip, er);
+}
+
+static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct inode *inode = &ip->i_inode;
+	int error = permission(inode, MAY_READ, NULL);
+	if (error)
+		return error;
+
+	return gfs2_ea_get_i(ip, er);
+}
+
+static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct inode *inode = &ip->i_inode;
+	int error = permission(inode, MAY_WRITE, NULL);
+	if (error)
+		return error;
+
+	return gfs2_ea_set_i(ip, er);
+}
+
+static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct inode *inode = &ip->i_inode;
+	int error = permission(inode, MAY_WRITE, NULL);
+	if (error)
+		return error;
+
+	return gfs2_ea_remove_i(ip, er);
+}
+
+static struct gfs2_eattr_operations gfs2_user_eaops = {
+	.eo_get = user_eo_get,
+	.eo_set = user_eo_set,
+	.eo_remove = user_eo_remove,
+	.eo_name = "user",
+};
+
+struct gfs2_eattr_operations gfs2_system_eaops = {
+	.eo_get = system_eo_get,
+	.eo_set = system_eo_set,
+	.eo_remove = system_eo_remove,
+	.eo_name = "system",
+};
+
+static struct gfs2_eattr_operations gfs2_security_eaops = {
+	.eo_get = security_eo_get,
+	.eo_set = security_eo_set,
+	.eo_remove = security_eo_remove,
+	.eo_name = "security",
+};
+
+struct gfs2_eattr_operations *gfs2_ea_ops[] = {
+	NULL,
+	&gfs2_user_eaops,
+	&gfs2_system_eaops,
+	&gfs2_security_eaops,
+};
+
diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h
new file mode 100644
index 0000000..508b4f7
--- /dev/null
+++ b/fs/gfs2/eaops.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __EAOPS_DOT_H__
+#define __EAOPS_DOT_H__
+
+struct gfs2_ea_request;
+struct gfs2_inode;
+
+struct gfs2_eattr_operations {
+	int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
+	int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
+	int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
+	char *eo_name;
+};
+
+unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);
+
+extern struct gfs2_eattr_operations gfs2_system_eaops;
+
+extern struct gfs2_eattr_operations *gfs2_ea_ops[];
+
+#endif /* __EAOPS_DOT_H__ */
+
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
new file mode 100644
index 0000000..a65a4cc
--- /dev/null
+++ b/fs/gfs2/eattr.c
@@ -0,0 +1,1501 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/xattr.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+/**
+ * ea_calc_size - returns the acutal number of bytes the request will take up
+ *                (not counting any unstuffed data blocks)
+ * @sdp:
+ * @er:
+ * @size:
+ *
+ * Returns: 1 if the EA should be stuffed
+ */
+
+static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er,
+			unsigned int *size)
+{
+	*size = GFS2_EAREQ_SIZE_STUFFED(er);
+	if (*size <= sdp->sd_jbsize)
+		return 1;
+
+	*size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er);
+
+	return 0;
+}
+
+static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er)
+{
+	unsigned int size;
+
+	if (er->er_data_len > GFS2_EA_MAX_DATA_LEN)
+		return -ERANGE;
+
+	ea_calc_size(sdp, er, &size);
+
+	/* This can only happen with 512 byte blocks */
+	if (size > sdp->sd_jbsize)
+		return -ERANGE;
+
+	return 0;
+}
+
+typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh,
+			  struct gfs2_ea_header *ea,
+			  struct gfs2_ea_header *prev, void *private);
+
+static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh,
+			ea_call_t ea_call, void *data)
+{
+	struct gfs2_ea_header *ea, *prev = NULL;
+	int error = 0;
+
+	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_EA))
+		return -EIO;
+
+	for (ea = GFS2_EA_BH2FIRST(bh);; prev = ea, ea = GFS2_EA2NEXT(ea)) {
+		if (!GFS2_EA_REC_LEN(ea))
+			goto fail;
+		if (!(bh->b_data <= (char *)ea && (char *)GFS2_EA2NEXT(ea) <=
+						  bh->b_data + bh->b_size))
+			goto fail;
+		if (!GFS2_EATYPE_VALID(ea->ea_type))
+			goto fail;
+
+		error = ea_call(ip, bh, ea, prev, data);
+		if (error)
+			return error;
+
+		if (GFS2_EA_IS_LAST(ea)) {
+			if ((char *)GFS2_EA2NEXT(ea) !=
+			    bh->b_data + bh->b_size)
+				goto fail;
+			break;
+		}
+	}
+
+	return error;
+
+fail:
+	gfs2_consist_inode(ip);
+	return -EIO;
+}
+
+static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data)
+{
+	struct buffer_head *bh, *eabh;
+	u64 *eablk, *end;
+	int error;
+
+	error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &bh);
+	if (error)
+		return error;
+
+	if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) {
+		error = ea_foreach_i(ip, bh, ea_call, data);
+		goto out;
+	}
+
+	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_IN)) {
+		error = -EIO;
+		goto out;
+	}
+
+	eablk = (u64 *)(bh->b_data + sizeof(struct gfs2_meta_header));
+	end = eablk + GFS2_SB(&ip->i_inode)->sd_inptrs;
+
+	for (; eablk < end; eablk++) {
+		u64 bn;
+
+		if (!*eablk)
+			break;
+		bn = be64_to_cpu(*eablk);
+
+		error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh);
+		if (error)
+			break;
+		error = ea_foreach_i(ip, eabh, ea_call, data);
+		brelse(eabh);
+		if (error)
+			break;
+	}
+out:
+	brelse(bh);
+	return error;
+}
+
+struct ea_find {
+	struct gfs2_ea_request *ef_er;
+	struct gfs2_ea_location *ef_el;
+};
+
+static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh,
+		     struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
+		     void *private)
+{
+	struct ea_find *ef = private;
+	struct gfs2_ea_request *er = ef->ef_er;
+
+	if (ea->ea_type == GFS2_EATYPE_UNUSED)
+		return 0;
+
+	if (ea->ea_type == er->er_type) {
+		if (ea->ea_name_len == er->er_name_len &&
+		    !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) {
+			struct gfs2_ea_location *el = ef->ef_el;
+			get_bh(bh);
+			el->el_bh = bh;
+			el->el_ea = ea;
+			el->el_prev = prev;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+		 struct gfs2_ea_location *el)
+{
+	struct ea_find ef;
+	int error;
+
+	ef.ef_er = er;
+	ef.ef_el = el;
+
+	memset(el, 0, sizeof(struct gfs2_ea_location));
+
+	error = ea_foreach(ip, ea_find_i, &ef);
+	if (error > 0)
+		return 0;
+
+	return error;
+}
+
+/**
+ * ea_dealloc_unstuffed -
+ * @ip:
+ * @bh:
+ * @ea:
+ * @prev:
+ * @private:
+ *
+ * Take advantage of the fact that all unstuffed blocks are
+ * allocated from the same RG.  But watch, this may not always
+ * be true.
+ *
+ * Returns: errno
+ */
+
+static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
+				struct gfs2_ea_header *ea,
+				struct gfs2_ea_header *prev, void *private)
+{
+	int *leave = private;
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_holder rg_gh;
+	struct buffer_head *dibh;
+	u64 *dataptrs, bn = 0;
+	u64 bstart = 0;
+	unsigned int blen = 0;
+	unsigned int blks = 0;
+	unsigned int x;
+	int error;
+
+	if (GFS2_EA_IS_STUFFED(ea))
+		return 0;
+
+	dataptrs = GFS2_EA2DATAPTRS(ea);
+	for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
+		if (*dataptrs) {
+			blks++;
+			bn = be64_to_cpu(*dataptrs);
+		}
+	}
+	if (!blks)
+		return 0;
+
+	rgd = gfs2_blk2rgrpd(sdp, bn);
+	if (!rgd) {
+		gfs2_consist_inode(ip);
+		return -EIO;
+	}
+
+	error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
+	if (error)
+		return error;
+
+	error = gfs2_trans_begin(sdp, rgd->rd_ri.ri_length + RES_DINODE +
+				 RES_EATTR + RES_STATFS + RES_QUOTA, blks);
+	if (error)
+		goto out_gunlock;
+
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+	dataptrs = GFS2_EA2DATAPTRS(ea);
+	for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
+		if (!*dataptrs)
+			break;
+		bn = be64_to_cpu(*dataptrs);
+
+		if (bstart + blen == bn)
+			blen++;
+		else {
+			if (bstart)
+				gfs2_free_meta(ip, bstart, blen);
+			bstart = bn;
+			blen = 1;
+		}
+
+		*dataptrs = 0;
+		if (!ip->i_di.di_blocks)
+			gfs2_consist_inode(ip);
+		ip->i_di.di_blocks--;
+	}
+	if (bstart)
+		gfs2_free_meta(ip, bstart, blen);
+
+	if (prev && !leave) {
+		u32 len;
+
+		len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
+		prev->ea_rec_len = cpu_to_be32(len);
+
+		if (GFS2_EA_IS_LAST(ea))
+			prev->ea_flags |= GFS2_EAFLAG_LAST;
+	} else {
+		ea->ea_type = GFS2_EATYPE_UNUSED;
+		ea->ea_num_ptrs = 0;
+	}
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		ip->i_di.di_ctime = get_seconds();
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(sdp);
+
+out_gunlock:
+	gfs2_glock_dq_uninit(&rg_gh);
+	return error;
+}
+
+static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
+			       struct gfs2_ea_header *ea,
+			       struct gfs2_ea_header *prev, int leave)
+{
+	struct gfs2_alloc *al;
+	int error;
+
+	al = gfs2_alloc_get(ip);
+
+	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out_alloc;
+
+	error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
+	if (error)
+		goto out_quota;
+
+	error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL);
+
+	gfs2_glock_dq_uninit(&al->al_ri_gh);
+
+out_quota:
+	gfs2_quota_unhold(ip);
+out_alloc:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
+struct ea_list {
+	struct gfs2_ea_request *ei_er;
+	unsigned int ei_size;
+};
+
+static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
+		     struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
+		     void *private)
+{
+	struct ea_list *ei = private;
+	struct gfs2_ea_request *er = ei->ei_er;
+	unsigned int ea_size = gfs2_ea_strlen(ea);
+
+	if (ea->ea_type == GFS2_EATYPE_UNUSED)
+		return 0;
+
+	if (er->er_data_len) {
+		char *prefix = NULL;
+		unsigned int l = 0;
+		char c = 0;
+
+		if (ei->ei_size + ea_size > er->er_data_len)
+			return -ERANGE;
+
+		switch (ea->ea_type) {
+		case GFS2_EATYPE_USR:
+			prefix = "user.";
+			l = 5;
+			break;
+		case GFS2_EATYPE_SYS:
+			prefix = "system.";
+			l = 7;
+			break;
+		case GFS2_EATYPE_SECURITY:
+			prefix = "security.";
+			l = 9;
+			break;
+		}
+
+		BUG_ON(l == 0);
+
+		memcpy(er->er_data + ei->ei_size, prefix, l);
+		memcpy(er->er_data + ei->ei_size + l, GFS2_EA2NAME(ea),
+		       ea->ea_name_len);
+		memcpy(er->er_data + ei->ei_size + ea_size - 1, &c, 1);
+	}
+
+	ei->ei_size += ea_size;
+
+	return 0;
+}
+
+/**
+ * gfs2_ea_list -
+ * @ip:
+ * @er:
+ *
+ * Returns: actual size of data on success, -errno on error
+ */
+
+int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct gfs2_holder i_gh;
+	int error;
+
+	if (!er->er_data || !er->er_data_len) {
+		er->er_data = NULL;
+		er->er_data_len = 0;
+	}
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+	if (error)
+		return error;
+
+	if (ip->i_di.di_eattr) {
+		struct ea_list ei = { .ei_er = er, .ei_size = 0 };
+
+		error = ea_foreach(ip, ea_list_i, &ei);
+		if (!error)
+			error = ei.ei_size;
+	}
+
+	gfs2_glock_dq_uninit(&i_gh);
+
+	return error;
+}
+
+/**
+ * ea_get_unstuffed - actually copies the unstuffed data into the
+ *                    request buffer
+ * @ip: The GFS2 inode
+ * @ea: The extended attribute header structure
+ * @data: The data to be copied
+ *
+ * Returns: errno
+ */
+
+static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
+			    char *data)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head **bh;
+	unsigned int amount = GFS2_EA_DATA_LEN(ea);
+	unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
+	u64 *dataptrs = GFS2_EA2DATAPTRS(ea);
+	unsigned int x;
+	int error = 0;
+
+	bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL);
+	if (!bh)
+		return -ENOMEM;
+
+	for (x = 0; x < nptrs; x++) {
+		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
+				       bh + x);
+		if (error) {
+			while (x--)
+				brelse(bh[x]);
+			goto out;
+		}
+		dataptrs++;
+	}
+
+	for (x = 0; x < nptrs; x++) {
+		error = gfs2_meta_wait(sdp, bh[x]);
+		if (error) {
+			for (; x < nptrs; x++)
+				brelse(bh[x]);
+			goto out;
+		}
+		if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
+			for (; x < nptrs; x++)
+				brelse(bh[x]);
+			error = -EIO;
+			goto out;
+		}
+
+		memcpy(data, bh[x]->b_data + sizeof(struct gfs2_meta_header),
+		       (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
+
+		amount -= sdp->sd_jbsize;
+		data += sdp->sd_jbsize;
+
+		brelse(bh[x]);
+	}
+
+out:
+	kfree(bh);
+	return error;
+}
+
+int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
+		     char *data)
+{
+	if (GFS2_EA_IS_STUFFED(el->el_ea)) {
+		memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea));
+		return 0;
+	} else
+		return ea_get_unstuffed(ip, el->el_ea, data);
+}
+
+/**
+ * gfs2_ea_get_i -
+ * @ip: The GFS2 inode
+ * @er: The request structure
+ *
+ * Returns: actual size of data on success, -errno on error
+ */
+
+int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct gfs2_ea_location el;
+	int error;
+
+	if (!ip->i_di.di_eattr)
+		return -ENODATA;
+
+	error = gfs2_ea_find(ip, er, &el);
+	if (error)
+		return error;
+	if (!el.el_ea)
+		return -ENODATA;
+
+	if (er->er_data_len) {
+		if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len)
+			error =  -ERANGE;
+		else
+			error = gfs2_ea_get_copy(ip, &el, er->er_data);
+	}
+	if (!error)
+		error = GFS2_EA_DATA_LEN(el.el_ea);
+
+	brelse(el.el_bh);
+
+	return error;
+}
+
+/**
+ * gfs2_ea_get -
+ * @ip: The GFS2 inode
+ * @er: The request structure
+ *
+ * Returns: actual size of data on success, -errno on error
+ */
+
+int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct gfs2_holder i_gh;
+	int error;
+
+	if (!er->er_name_len ||
+	    er->er_name_len > GFS2_EA_MAX_NAME_LEN)
+		return -EINVAL;
+	if (!er->er_data || !er->er_data_len) {
+		er->er_data = NULL;
+		er->er_data_len = 0;
+	}
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+	if (error)
+		return error;
+
+	error = gfs2_ea_ops[er->er_type]->eo_get(ip, er);
+
+	gfs2_glock_dq_uninit(&i_gh);
+
+	return error;
+}
+
+/**
+ * ea_alloc_blk - allocates a new block for extended attributes.
+ * @ip: A pointer to the inode that's getting extended attributes
+ * @bhp: Pointer to pointer to a struct buffer_head
+ *
+ * Returns: errno
+ */
+
+static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_ea_header *ea;
+	u64 block;
+
+	block = gfs2_alloc_meta(ip);
+
+	*bhp = gfs2_meta_new(ip->i_gl, block);
+	gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
+	gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
+	gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header));
+
+	ea = GFS2_EA_BH2FIRST(*bhp);
+	ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize);
+	ea->ea_type = GFS2_EATYPE_UNUSED;
+	ea->ea_flags = GFS2_EAFLAG_LAST;
+	ea->ea_num_ptrs = 0;
+
+	ip->i_di.di_blocks++;
+
+	return 0;
+}
+
+/**
+ * ea_write - writes the request info to an ea, creating new blocks if
+ *            necessary
+ * @ip: inode that is being modified
+ * @ea: the location of the new ea in a block
+ * @er: the write request
+ *
+ * Note: does not update ea_rec_len or the GFS2_EAFLAG_LAST bin of ea_flags
+ *
+ * returns : errno
+ */
+
+static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
+		    struct gfs2_ea_request *er)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+
+	ea->ea_data_len = cpu_to_be32(er->er_data_len);
+	ea->ea_name_len = er->er_name_len;
+	ea->ea_type = er->er_type;
+	ea->__pad = 0;
+
+	memcpy(GFS2_EA2NAME(ea), er->er_name, er->er_name_len);
+
+	if (GFS2_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) {
+		ea->ea_num_ptrs = 0;
+		memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len);
+	} else {
+		u64 *dataptr = GFS2_EA2DATAPTRS(ea);
+		const char *data = er->er_data;
+		unsigned int data_len = er->er_data_len;
+		unsigned int copy;
+		unsigned int x;
+
+		ea->ea_num_ptrs = DIV_ROUND_UP(er->er_data_len, sdp->sd_jbsize);
+		for (x = 0; x < ea->ea_num_ptrs; x++) {
+			struct buffer_head *bh;
+			u64 block;
+			int mh_size = sizeof(struct gfs2_meta_header);
+
+			block = gfs2_alloc_meta(ip);
+
+			bh = gfs2_meta_new(ip->i_gl, block);
+			gfs2_trans_add_bh(ip->i_gl, bh, 1);
+			gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED);
+
+			ip->i_di.di_blocks++;
+
+			copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize :
+							   data_len;
+			memcpy(bh->b_data + mh_size, data, copy);
+			if (copy < sdp->sd_jbsize)
+				memset(bh->b_data + mh_size + copy, 0,
+				       sdp->sd_jbsize - copy);
+
+			*dataptr++ = cpu_to_be64(bh->b_blocknr);
+			data += copy;
+			data_len -= copy;
+
+			brelse(bh);
+		}
+
+		gfs2_assert_withdraw(sdp, !data_len);
+	}
+
+	return 0;
+}
+
+typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip,
+				   struct gfs2_ea_request *er, void *private);
+
+static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+			     unsigned int blks,
+			     ea_skeleton_call_t skeleton_call, void *private)
+{
+	struct gfs2_alloc *al;
+	struct buffer_head *dibh;
+	int error;
+
+	al = gfs2_alloc_get(ip);
+
+	error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out;
+
+	error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+	if (error)
+		goto out_gunlock_q;
+
+	al->al_requested = blks;
+
+	error = gfs2_inplace_reserve(ip);
+	if (error)
+		goto out_gunlock_q;
+
+	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
+				 blks + al->al_rgd->rd_ri.ri_length +
+				 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
+	if (error)
+		goto out_ipres;
+
+	error = skeleton_call(ip, er, private);
+	if (error)
+		goto out_end_trans;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		if (er->er_flags & GFS2_ERF_MODE) {
+			gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
+					    (ip->i_di.di_mode & S_IFMT) ==
+					    (er->er_mode & S_IFMT));
+			ip->i_di.di_mode = er->er_mode;
+		}
+		ip->i_di.di_ctime = get_seconds();
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+out_end_trans:
+	gfs2_trans_end(GFS2_SB(&ip->i_inode));
+out_ipres:
+	gfs2_inplace_release(ip);
+out_gunlock_q:
+	gfs2_quota_unlock(ip);
+out:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
+static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+		     void *private)
+{
+	struct buffer_head *bh;
+	int error;
+
+	error = ea_alloc_blk(ip, &bh);
+	if (error)
+		return error;
+
+	ip->i_di.di_eattr = bh->b_blocknr;
+	error = ea_write(ip, GFS2_EA_BH2FIRST(bh), er);
+
+	brelse(bh);
+
+	return error;
+}
+
+/**
+ * ea_init - initializes a new eattr block
+ * @ip:
+ * @er:
+ *
+ * Returns: errno
+ */
+
+static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize;
+	unsigned int blks = 1;
+
+	if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize)
+		blks += DIV_ROUND_UP(er->er_data_len, jbsize);
+
+	return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL);
+}
+
+static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea)
+{
+	u32 ea_size = GFS2_EA_SIZE(ea);
+	struct gfs2_ea_header *new = (struct gfs2_ea_header *)((char *)ea +
+				     ea_size);
+	u32 new_size = GFS2_EA_REC_LEN(ea) - ea_size;
+	int last = ea->ea_flags & GFS2_EAFLAG_LAST;
+
+	ea->ea_rec_len = cpu_to_be32(ea_size);
+	ea->ea_flags ^= last;
+
+	new->ea_rec_len = cpu_to_be32(new_size);
+	new->ea_flags = last;
+
+	return new;
+}
+
+static void ea_set_remove_stuffed(struct gfs2_inode *ip,
+				  struct gfs2_ea_location *el)
+{
+	struct gfs2_ea_header *ea = el->el_ea;
+	struct gfs2_ea_header *prev = el->el_prev;
+	u32 len;
+
+	gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
+
+	if (!prev || !GFS2_EA_IS_STUFFED(ea)) {
+		ea->ea_type = GFS2_EATYPE_UNUSED;
+		return;
+	} else if (GFS2_EA2NEXT(prev) != ea) {
+		prev = GFS2_EA2NEXT(prev);
+		gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(prev) == ea);
+	}
+
+	len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
+	prev->ea_rec_len = cpu_to_be32(len);
+
+	if (GFS2_EA_IS_LAST(ea))
+		prev->ea_flags |= GFS2_EAFLAG_LAST;
+}
+
+struct ea_set {
+	int ea_split;
+
+	struct gfs2_ea_request *es_er;
+	struct gfs2_ea_location *es_el;
+
+	struct buffer_head *es_bh;
+	struct gfs2_ea_header *es_ea;
+};
+
+static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
+				 struct gfs2_ea_header *ea, struct ea_set *es)
+{
+	struct gfs2_ea_request *er = es->es_er;
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0);
+	if (error)
+		return error;
+
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+	if (es->ea_split)
+		ea = ea_split_ea(ea);
+
+	ea_write(ip, ea, er);
+
+	if (es->es_el)
+		ea_set_remove_stuffed(ip, es->es_el);
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto out;
+
+	if (er->er_flags & GFS2_ERF_MODE) {
+		gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
+			(ip->i_di.di_mode & S_IFMT) == (er->er_mode & S_IFMT));
+		ip->i_di.di_mode = er->er_mode;
+	}
+	ip->i_di.di_ctime = get_seconds();
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
+out:
+	gfs2_trans_end(GFS2_SB(&ip->i_inode));
+	return error;
+}
+
+static int ea_set_simple_alloc(struct gfs2_inode *ip,
+			       struct gfs2_ea_request *er, void *private)
+{
+	struct ea_set *es = private;
+	struct gfs2_ea_header *ea = es->es_ea;
+	int error;
+
+	gfs2_trans_add_bh(ip->i_gl, es->es_bh, 1);
+
+	if (es->ea_split)
+		ea = ea_split_ea(ea);
+
+	error = ea_write(ip, ea, er);
+	if (error)
+		return error;
+
+	if (es->es_el)
+		ea_set_remove_stuffed(ip, es->es_el);
+
+	return 0;
+}
+
+static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh,
+			 struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
+			 void *private)
+{
+	struct ea_set *es = private;
+	unsigned int size;
+	int stuffed;
+	int error;
+
+	stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size);
+
+	if (ea->ea_type == GFS2_EATYPE_UNUSED) {
+		if (GFS2_EA_REC_LEN(ea) < size)
+			return 0;
+		if (!GFS2_EA_IS_STUFFED(ea)) {
+			error = ea_remove_unstuffed(ip, bh, ea, prev, 1);
+			if (error)
+				return error;
+		}
+		es->ea_split = 0;
+	} else if (GFS2_EA_REC_LEN(ea) - GFS2_EA_SIZE(ea) >= size)
+		es->ea_split = 1;
+	else
+		return 0;
+
+	if (stuffed) {
+		error = ea_set_simple_noalloc(ip, bh, ea, es);
+		if (error)
+			return error;
+	} else {
+		unsigned int blks;
+
+		es->es_bh = bh;
+		es->es_ea = ea;
+		blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len,
+					GFS2_SB(&ip->i_inode)->sd_jbsize);
+
+		error = ea_alloc_skeleton(ip, es->es_er, blks,
+					  ea_set_simple_alloc, es);
+		if (error)
+			return error;
+	}
+
+	return 1;
+}
+
+static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+			void *private)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head *indbh, *newbh;
+	u64 *eablk;
+	int error;
+	int mh_size = sizeof(struct gfs2_meta_header);
+
+	if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) {
+		u64 *end;
+
+		error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT,
+				       &indbh);
+		if (error)
+			return error;
+
+		if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) {
+			error = -EIO;
+			goto out;
+		}
+
+		eablk = (u64 *)(indbh->b_data + mh_size);
+		end = eablk + sdp->sd_inptrs;
+
+		for (; eablk < end; eablk++)
+			if (!*eablk)
+				break;
+
+		if (eablk == end) {
+			error = -ENOSPC;
+			goto out;
+		}
+
+		gfs2_trans_add_bh(ip->i_gl, indbh, 1);
+	} else {
+		u64 blk;
+
+		blk = gfs2_alloc_meta(ip);
+
+		indbh = gfs2_meta_new(ip->i_gl, blk);
+		gfs2_trans_add_bh(ip->i_gl, indbh, 1);
+		gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+		gfs2_buffer_clear_tail(indbh, mh_size);
+
+		eablk = (u64 *)(indbh->b_data + mh_size);
+		*eablk = cpu_to_be64(ip->i_di.di_eattr);
+		ip->i_di.di_eattr = blk;
+		ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT;
+		ip->i_di.di_blocks++;
+
+		eablk++;
+	}
+
+	error = ea_alloc_blk(ip, &newbh);
+	if (error)
+		goto out;
+
+	*eablk = cpu_to_be64((u64)newbh->b_blocknr);
+	error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er);
+	brelse(newbh);
+	if (error)
+		goto out;
+
+	if (private)
+		ea_set_remove_stuffed(ip, private);
+
+out:
+	brelse(indbh);
+	return error;
+}
+
+static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+		    struct gfs2_ea_location *el)
+{
+	struct ea_set es;
+	unsigned int blks = 2;
+	int error;
+
+	memset(&es, 0, sizeof(struct ea_set));
+	es.es_er = er;
+	es.es_el = el;
+
+	error = ea_foreach(ip, ea_set_simple, &es);
+	if (error > 0)
+		return 0;
+	if (error)
+		return error;
+
+	if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT))
+		blks++;
+	if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize)
+		blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize);
+
+	return ea_alloc_skeleton(ip, er, blks, ea_set_block, el);
+}
+
+static int ea_set_remove_unstuffed(struct gfs2_inode *ip,
+				   struct gfs2_ea_location *el)
+{
+	if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) {
+		el->el_prev = GFS2_EA2NEXT(el->el_prev);
+		gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
+				     GFS2_EA2NEXT(el->el_prev) == el->el_ea);
+	}
+
+	return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0);
+}
+
+int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct gfs2_ea_location el;
+	int error;
+
+	if (!ip->i_di.di_eattr) {
+		if (er->er_flags & XATTR_REPLACE)
+			return -ENODATA;
+		return ea_init(ip, er);
+	}
+
+	error = gfs2_ea_find(ip, er, &el);
+	if (error)
+		return error;
+
+	if (el.el_ea) {
+		if (ip->i_di.di_flags & GFS2_DIF_APPENDONLY) {
+			brelse(el.el_bh);
+			return -EPERM;
+		}
+
+		error = -EEXIST;
+		if (!(er->er_flags & XATTR_CREATE)) {
+			int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea);
+			error = ea_set_i(ip, er, &el);
+			if (!error && unstuffed)
+				ea_set_remove_unstuffed(ip, &el);
+		}
+
+		brelse(el.el_bh);
+	} else {
+		error = -ENODATA;
+		if (!(er->er_flags & XATTR_REPLACE))
+			error = ea_set_i(ip, er, NULL);
+	}
+
+	return error;
+}
+
+int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct gfs2_holder i_gh;
+	int error;
+
+	if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
+		return -EINVAL;
+	if (!er->er_data || !er->er_data_len) {
+		er->er_data = NULL;
+		er->er_data_len = 0;
+	}
+	error = ea_check_size(GFS2_SB(&ip->i_inode), er);
+	if (error)
+		return error;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+	if (error)
+		return error;
+
+	if (IS_IMMUTABLE(&ip->i_inode))
+		error = -EPERM;
+	else
+		error = gfs2_ea_ops[er->er_type]->eo_set(ip, er);
+
+	gfs2_glock_dq_uninit(&i_gh);
+
+	return error;
+}
+
+static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
+{
+	struct gfs2_ea_header *ea = el->el_ea;
+	struct gfs2_ea_header *prev = el->el_prev;
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
+	if (error)
+		return error;
+
+	gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
+
+	if (prev) {
+		u32 len;
+
+		len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
+		prev->ea_rec_len = cpu_to_be32(len);
+
+		if (GFS2_EA_IS_LAST(ea))
+			prev->ea_flags |= GFS2_EAFLAG_LAST;
+	} else
+		ea->ea_type = GFS2_EATYPE_UNUSED;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		ip->i_di.di_ctime = get_seconds();
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(GFS2_SB(&ip->i_inode));
+
+	return error;
+}
+
+int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct gfs2_ea_location el;
+	int error;
+
+	if (!ip->i_di.di_eattr)
+		return -ENODATA;
+
+	error = gfs2_ea_find(ip, er, &el);
+	if (error)
+		return error;
+	if (!el.el_ea)
+		return -ENODATA;
+
+	if (GFS2_EA_IS_STUFFED(el.el_ea))
+		error = ea_remove_stuffed(ip, &el);
+	else
+		error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev,
+					    0);
+
+	brelse(el.el_bh);
+
+	return error;
+}
+
+/**
+ * gfs2_ea_remove - sets (or creates or replaces) an extended attribute
+ * @ip: pointer to the inode of the target file
+ * @er: request information
+ *
+ * Returns: errno
+ */
+
+int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+	struct gfs2_holder i_gh;
+	int error;
+
+	if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
+		return -EINVAL;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+	if (error)
+		return error;
+
+	if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
+		error = -EPERM;
+	else
+		error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er);
+
+	gfs2_glock_dq_uninit(&i_gh);
+
+	return error;
+}
+
+static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
+				  struct gfs2_ea_header *ea, char *data)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct buffer_head **bh;
+	unsigned int amount = GFS2_EA_DATA_LEN(ea);
+	unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
+	u64 *dataptrs = GFS2_EA2DATAPTRS(ea);
+	unsigned int x;
+	int error;
+
+	bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL);
+	if (!bh)
+		return -ENOMEM;
+
+	error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
+	if (error)
+		goto out;
+
+	for (x = 0; x < nptrs; x++) {
+		error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
+				       bh + x);
+		if (error) {
+			while (x--)
+				brelse(bh[x]);
+			goto fail;
+		}
+		dataptrs++;
+	}
+
+	for (x = 0; x < nptrs; x++) {
+		error = gfs2_meta_wait(sdp, bh[x]);
+		if (error) {
+			for (; x < nptrs; x++)
+				brelse(bh[x]);
+			goto fail;
+		}
+		if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
+			for (; x < nptrs; x++)
+				brelse(bh[x]);
+			error = -EIO;
+			goto fail;
+		}
+
+		gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
+
+		memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data,
+		       (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
+
+		amount -= sdp->sd_jbsize;
+		data += sdp->sd_jbsize;
+
+		brelse(bh[x]);
+	}
+
+out:
+	kfree(bh);
+	return error;
+
+fail:
+	gfs2_trans_end(sdp);
+	kfree(bh);
+	return error;
+}
+
+int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
+		      struct iattr *attr, char *data)
+{
+	struct buffer_head *dibh;
+	int error;
+
+	if (GFS2_EA_IS_STUFFED(el->el_ea)) {
+		error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
+		if (error)
+			return error;
+
+		gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
+		memcpy(GFS2_EA2DATA(el->el_ea), data,
+		       GFS2_EA_DATA_LEN(el->el_ea));
+	} else
+		error = ea_acl_chmod_unstuffed(ip, el->el_ea, data);
+
+	if (error)
+		return error;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		error = inode_setattr(&ip->i_inode, attr);
+		gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
+		gfs2_inode_attr_out(ip);
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(GFS2_SB(&ip->i_inode));
+
+	return error;
+}
+
+static int ea_dealloc_indirect(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_rgrp_list rlist;
+	struct buffer_head *indbh, *dibh;
+	u64 *eablk, *end;
+	unsigned int rg_blocks = 0;
+	u64 bstart = 0;
+	unsigned int blen = 0;
+	unsigned int blks = 0;
+	unsigned int x;
+	int error;
+
+	memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
+
+	error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &indbh);
+	if (error)
+		return error;
+
+	if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) {
+		error = -EIO;
+		goto out;
+	}
+
+	eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header));
+	end = eablk + sdp->sd_inptrs;
+
+	for (; eablk < end; eablk++) {
+		u64 bn;
+
+		if (!*eablk)
+			break;
+		bn = be64_to_cpu(*eablk);
+
+		if (bstart + blen == bn)
+			blen++;
+		else {
+			if (bstart)
+				gfs2_rlist_add(sdp, &rlist, bstart);
+			bstart = bn;
+			blen = 1;
+		}
+		blks++;
+	}
+	if (bstart)
+		gfs2_rlist_add(sdp, &rlist, bstart);
+	else
+		goto out;
+
+	gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
+
+	for (x = 0; x < rlist.rl_rgrps; x++) {
+		struct gfs2_rgrpd *rgd;
+		rgd = rlist.rl_ghs[x].gh_gl->gl_object;
+		rg_blocks += rgd->rd_ri.ri_length;
+	}
+
+	error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
+	if (error)
+		goto out_rlist_free;
+
+	error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + RES_INDIRECT +
+				 RES_STATFS + RES_QUOTA, blks);
+	if (error)
+		goto out_gunlock;
+
+	gfs2_trans_add_bh(ip->i_gl, indbh, 1);
+
+	eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header));
+	bstart = 0;
+	blen = 0;
+
+	for (; eablk < end; eablk++) {
+		u64 bn;
+
+		if (!*eablk)
+			break;
+		bn = be64_to_cpu(*eablk);
+
+		if (bstart + blen == bn)
+			blen++;
+		else {
+			if (bstart)
+				gfs2_free_meta(ip, bstart, blen);
+			bstart = bn;
+			blen = 1;
+		}
+
+		*eablk = 0;
+		if (!ip->i_di.di_blocks)
+			gfs2_consist_inode(ip);
+		ip->i_di.di_blocks--;
+	}
+	if (bstart)
+		gfs2_free_meta(ip, bstart, blen);
+
+	ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(sdp);
+
+out_gunlock:
+	gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
+out_rlist_free:
+	gfs2_rlist_free(&rlist);
+out:
+	brelse(indbh);
+	return error;
+}
+
+static int ea_dealloc_block(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_rgrpd *rgd;
+	struct buffer_head *dibh;
+	int error;
+
+	rgd = gfs2_blk2rgrpd(sdp, ip->i_di.di_eattr);
+	if (!rgd) {
+		gfs2_consist_inode(ip);
+		return -EIO;
+	}
+
+	error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
+				   &al->al_rgd_gh);
+	if (error)
+		return error;
+
+	error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + RES_STATFS +
+				 RES_QUOTA, 1);
+	if (error)
+		goto out_gunlock;
+
+	gfs2_free_meta(ip, ip->i_di.di_eattr, 1);
+
+	ip->i_di.di_eattr = 0;
+	if (!ip->i_di.di_blocks)
+		gfs2_consist_inode(ip);
+	ip->i_di.di_blocks--;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(sdp);
+
+out_gunlock:
+	gfs2_glock_dq_uninit(&al->al_rgd_gh);
+	return error;
+}
+
+/**
+ * gfs2_ea_dealloc - deallocate the extended attribute fork
+ * @ip: the inode
+ *
+ * Returns: errno
+ */
+
+int gfs2_ea_dealloc(struct gfs2_inode *ip)
+{
+	struct gfs2_alloc *al;
+	int error;
+
+	al = gfs2_alloc_get(ip);
+
+	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out_alloc;
+
+	error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
+	if (error)
+		goto out_quota;
+
+	error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
+	if (error)
+		goto out_rindex;
+
+	if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) {
+		error = ea_dealloc_indirect(ip);
+		if (error)
+			goto out_rindex;
+	}
+
+	error = ea_dealloc_block(ip);
+
+out_rindex:
+	gfs2_glock_dq_uninit(&al->al_ri_gh);
+out_quota:
+	gfs2_quota_unhold(ip);
+out_alloc:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h
new file mode 100644
index 0000000..ffa6594
--- /dev/null
+++ b/fs/gfs2/eattr.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __EATTR_DOT_H__
+#define __EATTR_DOT_H__
+
+struct gfs2_inode;
+struct iattr;
+
+#define GFS2_EA_REC_LEN(ea) be32_to_cpu((ea)->ea_rec_len)
+#define GFS2_EA_DATA_LEN(ea) be32_to_cpu((ea)->ea_data_len)
+
+#define GFS2_EA_SIZE(ea) \
+ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \
+      ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \
+                                  (sizeof(u64) * (ea)->ea_num_ptrs)), 8)
+
+#define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs)
+#define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST)
+
+#define GFS2_EAREQ_SIZE_STUFFED(er) \
+ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8)
+
+#define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \
+ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \
+      sizeof(u64) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8)
+
+#define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1))
+#define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len)
+
+#define GFS2_EA2DATAPTRS(ea) \
+((u64 *)(GFS2_EA2NAME(ea) + ALIGN((ea)->ea_name_len, 8)))
+
+#define GFS2_EA2NEXT(ea) \
+((struct gfs2_ea_header *)((char *)(ea) + GFS2_EA_REC_LEN(ea)))
+
+#define GFS2_EA_BH2FIRST(bh) \
+((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header)))
+
+#define GFS2_ERF_MODE 0x80000000
+
+struct gfs2_ea_request {
+	const char *er_name;
+	char *er_data;
+	unsigned int er_name_len;
+	unsigned int er_data_len;
+	unsigned int er_type; /* GFS2_EATYPE_... */
+	int er_flags;
+	mode_t er_mode;
+};
+
+struct gfs2_ea_location {
+	struct buffer_head *el_bh;
+	struct gfs2_ea_header *el_ea;
+	struct gfs2_ea_header *el_prev;
+};
+
+int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+
+int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+
+int gfs2_ea_dealloc(struct gfs2_inode *ip);
+
+/* Exported to acl.c */
+
+int gfs2_ea_find(struct gfs2_inode *ip,
+		 struct gfs2_ea_request *er,
+		 struct gfs2_ea_location *el);
+int gfs2_ea_get_copy(struct gfs2_inode *ip,
+		     struct gfs2_ea_location *el,
+		     char *data);
+int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
+		      struct iattr *attr, char *data);
+
+static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea)
+{
+	switch (ea->ea_type) {
+	case GFS2_EATYPE_USR:
+		return 5 + ea->ea_name_len + 1;
+	case GFS2_EATYPE_SYS:
+		return 7 + ea->ea_name_len + 1;
+	case GFS2_EATYPE_SECURITY:
+		return 9 + ea->ea_name_len + 1;
+	default:
+		return 0;
+	}
+}
+
+#endif /* __EATTR_DOT_H__ */
diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h
new file mode 100644
index 0000000..3bb11c0
--- /dev/null
+++ b/fs/gfs2/gfs2.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __GFS2_DOT_H__
+#define __GFS2_DOT_H__
+
+enum {
+	NO_CREATE = 0,
+	CREATE = 1,
+};
+
+enum {
+	NO_WAIT = 0,
+	WAIT = 1,
+};
+
+enum {
+	NO_FORCE = 0,
+	FORCE = 1,
+};
+
+#define GFS2_FAST_NAME_SIZE 8
+
+#endif /* __GFS2_DOT_H__ */
+
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
new file mode 100644
index 0000000..78fe0fa
--- /dev/null
+++ b/fs/gfs2/glock.c
@@ -0,0 +1,2231 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/delay.h>
+#include <linux/sort.h>
+#include <linux/jhash.h>
+#include <linux/kallsyms.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/list.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "lm.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "super.h"
+#include "util.h"
+
+struct greedy {
+	struct gfs2_holder gr_gh;
+	struct work_struct gr_work;
+};
+
+struct gfs2_gl_hash_bucket {
+        struct hlist_head hb_list;
+};
+
+typedef void (*glock_examiner) (struct gfs2_glock * gl);
+
+static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
+static int dump_glock(struct gfs2_glock *gl);
+static int dump_inode(struct gfs2_inode *ip);
+
+#define GFS2_GL_HASH_SHIFT      15
+#define GFS2_GL_HASH_SIZE       (1 << GFS2_GL_HASH_SHIFT)
+#define GFS2_GL_HASH_MASK       (GFS2_GL_HASH_SIZE - 1)
+
+static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE];
+
+/*
+ * Despite what you might think, the numbers below are not arbitrary :-)
+ * They are taken from the ipv4 routing hash code, which is well tested
+ * and thus should be nearly optimal. Later on we might tweek the numbers
+ * but for now this should be fine.
+ *
+ * The reason for putting the locks in a separate array from the list heads
+ * is that we can have fewer locks than list heads and save memory. We use
+ * the same hash function for both, but with a different hash mask.
+ */
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
+	defined(CONFIG_PROVE_LOCKING)
+
+#ifdef CONFIG_LOCKDEP
+# define GL_HASH_LOCK_SZ        256
+#else
+# if NR_CPUS >= 32
+#  define GL_HASH_LOCK_SZ       4096
+# elif NR_CPUS >= 16
+#  define GL_HASH_LOCK_SZ       2048
+# elif NR_CPUS >= 8
+#  define GL_HASH_LOCK_SZ       1024
+# elif NR_CPUS >= 4
+#  define GL_HASH_LOCK_SZ       512
+# else
+#  define GL_HASH_LOCK_SZ       256
+# endif
+#endif
+
+/* We never want more locks than chains */
+#if GFS2_GL_HASH_SIZE < GL_HASH_LOCK_SZ
+# undef GL_HASH_LOCK_SZ
+# define GL_HASH_LOCK_SZ GFS2_GL_HASH_SIZE
+#endif
+
+static rwlock_t gl_hash_locks[GL_HASH_LOCK_SZ];
+
+static inline rwlock_t *gl_lock_addr(unsigned int x)
+{
+	return &gl_hash_locks[x & (GL_HASH_LOCK_SZ-1)];
+}
+#else /* not SMP, so no spinlocks required */
+static inline rwlock_t *gl_lock_addr(x)
+{
+	return NULL;
+}
+#endif
+
+/**
+ * relaxed_state_ok - is a requested lock compatible with the current lock mode?
+ * @actual: the current state of the lock
+ * @requested: the lock state that was requested by the caller
+ * @flags: the modifier flags passed in by the caller
+ *
+ * Returns: 1 if the locks are compatible, 0 otherwise
+ */
+
+static inline int relaxed_state_ok(unsigned int actual, unsigned requested,
+				   int flags)
+{
+	if (actual == requested)
+		return 1;
+
+	if (flags & GL_EXACT)
+		return 0;
+
+	if (actual == LM_ST_EXCLUSIVE && requested == LM_ST_SHARED)
+		return 1;
+
+	if (actual != LM_ST_UNLOCKED && (flags & LM_FLAG_ANY))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * gl_hash() - Turn glock number into hash bucket number
+ * @lock: The glock number
+ *
+ * Returns: The number of the corresponding hash bucket
+ */
+
+static unsigned int gl_hash(const struct gfs2_sbd *sdp,
+			    const struct lm_lockname *name)
+{
+	unsigned int h;
+
+	h = jhash(&name->ln_number, sizeof(u64), 0);
+	h = jhash(&name->ln_type, sizeof(unsigned int), h);
+	h = jhash(&sdp, sizeof(struct gfs2_sbd *), h);
+	h &= GFS2_GL_HASH_MASK;
+
+	return h;
+}
+
+/**
+ * glock_free() - Perform a few checks and then release struct gfs2_glock
+ * @gl: The glock to release
+ *
+ * Also calls lock module to release its internal structure for this glock.
+ *
+ */
+
+static void glock_free(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	struct inode *aspace = gl->gl_aspace;
+
+	gfs2_lm_put_lock(sdp, gl->gl_lock);
+
+	if (aspace)
+		gfs2_aspace_put(aspace);
+
+	kmem_cache_free(gfs2_glock_cachep, gl);
+}
+
+/**
+ * gfs2_glock_hold() - increment reference count on glock
+ * @gl: The glock to hold
+ *
+ */
+
+void gfs2_glock_hold(struct gfs2_glock *gl)
+{
+	atomic_inc(&gl->gl_ref);
+}
+
+/**
+ * gfs2_glock_put() - Decrement reference count on glock
+ * @gl: The glock to put
+ *
+ */
+
+int gfs2_glock_put(struct gfs2_glock *gl)
+{
+	int rv = 0;
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+
+	write_lock(gl_lock_addr(gl->gl_hash));
+	if (atomic_dec_and_test(&gl->gl_ref)) {
+		hlist_del(&gl->gl_list);
+		write_unlock(gl_lock_addr(gl->gl_hash));
+		BUG_ON(spin_is_locked(&gl->gl_spin));
+		gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED);
+		gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
+		gfs2_assert(sdp, list_empty(&gl->gl_holders));
+		gfs2_assert(sdp, list_empty(&gl->gl_waiters1));
+		gfs2_assert(sdp, list_empty(&gl->gl_waiters2));
+		gfs2_assert(sdp, list_empty(&gl->gl_waiters3));
+		glock_free(gl);
+		rv = 1;
+		goto out;
+	}
+	write_unlock(gl_lock_addr(gl->gl_hash));
+out:
+	return rv;
+}
+
+/**
+ * queue_empty - check to see if a glock's queue is empty
+ * @gl: the glock
+ * @head: the head of the queue to check
+ *
+ * This function protects the list in the event that a process already
+ * has a holder on the list and is adding a second holder for itself.
+ * The glmutex lock is what generally prevents processes from working
+ * on the same glock at once, but the special case of adding a second
+ * holder for yourself ("recursive" locking) doesn't involve locking
+ * glmutex, making the spin lock necessary.
+ *
+ * Returns: 1 if the queue is empty
+ */
+
+static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head)
+{
+	int empty;
+	spin_lock(&gl->gl_spin);
+	empty = list_empty(head);
+	spin_unlock(&gl->gl_spin);
+	return empty;
+}
+
+/**
+ * search_bucket() - Find struct gfs2_glock by lock number
+ * @bucket: the bucket to search
+ * @name: The lock name
+ *
+ * Returns: NULL, or the struct gfs2_glock with the requested number
+ */
+
+static struct gfs2_glock *search_bucket(unsigned int hash,
+					const struct gfs2_sbd *sdp,
+					const struct lm_lockname *name)
+{
+	struct gfs2_glock *gl;
+	struct hlist_node *h;
+
+	hlist_for_each_entry(gl, h, &gl_hash_table[hash].hb_list, gl_list) {
+		if (!lm_name_equal(&gl->gl_name, name))
+			continue;
+		if (gl->gl_sbd != sdp)
+			continue;
+
+		atomic_inc(&gl->gl_ref);
+
+		return gl;
+	}
+
+	return NULL;
+}
+
+/**
+ * gfs2_glock_find() - Find glock by lock number
+ * @sdp: The GFS2 superblock
+ * @name: The lock name
+ *
+ * Returns: NULL, or the struct gfs2_glock with the requested number
+ */
+
+static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,
+					  const struct lm_lockname *name)
+{
+	unsigned int hash = gl_hash(sdp, name);
+	struct gfs2_glock *gl;
+
+	read_lock(gl_lock_addr(hash));
+	gl = search_bucket(hash, sdp, name);
+	read_unlock(gl_lock_addr(hash));
+
+	return gl;
+}
+
+/**
+ * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
+ * @sdp: The GFS2 superblock
+ * @number: the lock number
+ * @glops: The glock_operations to use
+ * @create: If 0, don't create the glock if it doesn't exist
+ * @glp: the glock is returned here
+ *
+ * This does not lock a glock, just finds/creates structures for one.
+ *
+ * Returns: errno
+ */
+
+int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
+		   const struct gfs2_glock_operations *glops, int create,
+		   struct gfs2_glock **glp)
+{
+	struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type };
+	struct gfs2_glock *gl, *tmp;
+	unsigned int hash = gl_hash(sdp, &name);
+	int error;
+
+	read_lock(gl_lock_addr(hash));
+	gl = search_bucket(hash, sdp, &name);
+	read_unlock(gl_lock_addr(hash));
+
+	if (gl || !create) {
+		*glp = gl;
+		return 0;
+	}
+
+	gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL);
+	if (!gl)
+		return -ENOMEM;
+
+	gl->gl_flags = 0;
+	gl->gl_name = name;
+	atomic_set(&gl->gl_ref, 1);
+	gl->gl_state = LM_ST_UNLOCKED;
+	gl->gl_hash = hash;
+	gl->gl_owner = NULL;
+	gl->gl_ip = 0;
+	gl->gl_ops = glops;
+	gl->gl_req_gh = NULL;
+	gl->gl_req_bh = NULL;
+	gl->gl_vn = 0;
+	gl->gl_stamp = jiffies;
+	gl->gl_object = NULL;
+	gl->gl_sbd = sdp;
+	gl->gl_aspace = NULL;
+	lops_init_le(&gl->gl_le, &gfs2_glock_lops);
+
+	/* If this glock protects actual on-disk data or metadata blocks,
+	   create a VFS inode to manage the pages/buffers holding them. */
+	if (glops == &gfs2_inode_glops || glops == &gfs2_rgrp_glops) {
+		gl->gl_aspace = gfs2_aspace_get(sdp);
+		if (!gl->gl_aspace) {
+			error = -ENOMEM;
+			goto fail;
+		}
+	}
+
+	error = gfs2_lm_get_lock(sdp, &name, &gl->gl_lock);
+	if (error)
+		goto fail_aspace;
+
+	write_lock(gl_lock_addr(hash));
+	tmp = search_bucket(hash, sdp, &name);
+	if (tmp) {
+		write_unlock(gl_lock_addr(hash));
+		glock_free(gl);
+		gl = tmp;
+	} else {
+		hlist_add_head(&gl->gl_list, &gl_hash_table[hash].hb_list);
+		write_unlock(gl_lock_addr(hash));
+	}
+
+	*glp = gl;
+
+	return 0;
+
+fail_aspace:
+	if (gl->gl_aspace)
+		gfs2_aspace_put(gl->gl_aspace);
+fail:
+	kmem_cache_free(gfs2_glock_cachep, gl);
+	return error;
+}
+
+/**
+ * gfs2_holder_init - initialize a struct gfs2_holder in the default way
+ * @gl: the glock
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gh: the holder structure
+ *
+ */
+
+void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
+		      struct gfs2_holder *gh)
+{
+	INIT_LIST_HEAD(&gh->gh_list);
+	gh->gh_gl = gl;
+	gh->gh_ip = (unsigned long)__builtin_return_address(0);
+	gh->gh_owner = current;
+	gh->gh_state = state;
+	gh->gh_flags = flags;
+	gh->gh_error = 0;
+	gh->gh_iflags = 0;
+	init_completion(&gh->gh_wait);
+
+	if (gh->gh_state == LM_ST_EXCLUSIVE)
+		gh->gh_flags |= GL_LOCAL_EXCL;
+
+	gfs2_glock_hold(gl);
+}
+
+/**
+ * gfs2_holder_reinit - reinitialize a struct gfs2_holder so we can requeue it
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gh: the holder structure
+ *
+ * Don't mess with the glock.
+ *
+ */
+
+void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh)
+{
+	gh->gh_state = state;
+	gh->gh_flags = flags;
+	if (gh->gh_state == LM_ST_EXCLUSIVE)
+		gh->gh_flags |= GL_LOCAL_EXCL;
+
+	gh->gh_iflags &= 1 << HIF_ALLOCED;
+	gh->gh_ip = (unsigned long)__builtin_return_address(0);
+}
+
+/**
+ * gfs2_holder_uninit - uninitialize a holder structure (drop glock reference)
+ * @gh: the holder structure
+ *
+ */
+
+void gfs2_holder_uninit(struct gfs2_holder *gh)
+{
+	gfs2_glock_put(gh->gh_gl);
+	gh->gh_gl = NULL;
+	gh->gh_ip = 0;
+}
+
+/**
+ * gfs2_holder_get - get a struct gfs2_holder structure
+ * @gl: the glock
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gfp_flags:
+ *
+ * Figure out how big an impact this function has.  Either:
+ * 1) Replace it with a cache of structures hanging off the struct gfs2_sbd
+ * 2) Leave it like it is
+ *
+ * Returns: the holder structure, NULL on ENOMEM
+ */
+
+static struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl,
+					   unsigned int state,
+					   int flags, gfp_t gfp_flags)
+{
+	struct gfs2_holder *gh;
+
+	gh = kmalloc(sizeof(struct gfs2_holder), gfp_flags);
+	if (!gh)
+		return NULL;
+
+	gfs2_holder_init(gl, state, flags, gh);
+	set_bit(HIF_ALLOCED, &gh->gh_iflags);
+	gh->gh_ip = (unsigned long)__builtin_return_address(0);
+	return gh;
+}
+
+/**
+ * gfs2_holder_put - get rid of a struct gfs2_holder structure
+ * @gh: the holder structure
+ *
+ */
+
+static void gfs2_holder_put(struct gfs2_holder *gh)
+{
+	gfs2_holder_uninit(gh);
+	kfree(gh);
+}
+
+/**
+ * rq_mutex - process a mutex request in the queue
+ * @gh: the glock holder
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_mutex(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+
+	list_del_init(&gh->gh_list);
+	/*  gh->gh_error never examined.  */
+	set_bit(GLF_LOCK, &gl->gl_flags);
+	complete(&gh->gh_wait);
+
+	return 1;
+}
+
+/**
+ * rq_promote - process a promote request in the queue
+ * @gh: the glock holder
+ *
+ * Acquire a new inter-node lock, or change a lock state to more restrictive.
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_promote(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+	if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
+		if (list_empty(&gl->gl_holders)) {
+			gl->gl_req_gh = gh;
+			set_bit(GLF_LOCK, &gl->gl_flags);
+			spin_unlock(&gl->gl_spin);
+
+			if (atomic_read(&sdp->sd_reclaim_count) >
+			    gfs2_tune_get(sdp, gt_reclaim_limit) &&
+			    !(gh->gh_flags & LM_FLAG_PRIORITY)) {
+				gfs2_reclaim_glock(sdp);
+				gfs2_reclaim_glock(sdp);
+			}
+
+			glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+			spin_lock(&gl->gl_spin);
+		}
+		return 1;
+	}
+
+	if (list_empty(&gl->gl_holders)) {
+		set_bit(HIF_FIRST, &gh->gh_iflags);
+		set_bit(GLF_LOCK, &gl->gl_flags);
+	} else {
+		struct gfs2_holder *next_gh;
+		if (gh->gh_flags & GL_LOCAL_EXCL)
+			return 1;
+		next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder,
+				     gh_list);
+		if (next_gh->gh_flags & GL_LOCAL_EXCL)
+			 return 1;
+	}
+
+	list_move_tail(&gh->gh_list, &gl->gl_holders);
+	gh->gh_error = 0;
+	set_bit(HIF_HOLDER, &gh->gh_iflags);
+
+	complete(&gh->gh_wait);
+
+	return 0;
+}
+
+/**
+ * rq_demote - process a demote request in the queue
+ * @gh: the glock holder
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_demote(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+	if (!list_empty(&gl->gl_holders))
+		return 1;
+
+	if (gl->gl_state == gh->gh_state || gl->gl_state == LM_ST_UNLOCKED) {
+		list_del_init(&gh->gh_list);
+		gh->gh_error = 0;
+		spin_unlock(&gl->gl_spin);
+		if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
+			gfs2_holder_put(gh);
+		else
+			complete(&gh->gh_wait);
+		spin_lock(&gl->gl_spin);
+	} else {
+		gl->gl_req_gh = gh;
+		set_bit(GLF_LOCK, &gl->gl_flags);
+		spin_unlock(&gl->gl_spin);
+
+		if (gh->gh_state == LM_ST_UNLOCKED ||
+		    gl->gl_state != LM_ST_EXCLUSIVE)
+			glops->go_drop_th(gl);
+		else
+			glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+
+		spin_lock(&gl->gl_spin);
+	}
+
+	return 0;
+}
+
+/**
+ * rq_greedy - process a queued request to drop greedy status
+ * @gh: the glock holder
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_greedy(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+
+	list_del_init(&gh->gh_list);
+	/*  gh->gh_error never examined.  */
+	clear_bit(GLF_GREEDY, &gl->gl_flags);
+	spin_unlock(&gl->gl_spin);
+
+	gfs2_holder_uninit(gh);
+	kfree(container_of(gh, struct greedy, gr_gh));
+
+	spin_lock(&gl->gl_spin);
+
+	return 0;
+}
+
+/**
+ * run_queue - process holder structures on a glock
+ * @gl: the glock
+ *
+ */
+static void run_queue(struct gfs2_glock *gl)
+{
+	struct gfs2_holder *gh;
+	int blocked = 1;
+
+	for (;;) {
+		if (test_bit(GLF_LOCK, &gl->gl_flags))
+			break;
+
+		if (!list_empty(&gl->gl_waiters1)) {
+			gh = list_entry(gl->gl_waiters1.next,
+					struct gfs2_holder, gh_list);
+
+			if (test_bit(HIF_MUTEX, &gh->gh_iflags))
+				blocked = rq_mutex(gh);
+			else
+				gfs2_assert_warn(gl->gl_sbd, 0);
+
+		} else if (!list_empty(&gl->gl_waiters2) &&
+			   !test_bit(GLF_SKIP_WAITERS2, &gl->gl_flags)) {
+			gh = list_entry(gl->gl_waiters2.next,
+					struct gfs2_holder, gh_list);
+
+			if (test_bit(HIF_DEMOTE, &gh->gh_iflags))
+				blocked = rq_demote(gh);
+			else if (test_bit(HIF_GREEDY, &gh->gh_iflags))
+				blocked = rq_greedy(gh);
+			else
+				gfs2_assert_warn(gl->gl_sbd, 0);
+
+		} else if (!list_empty(&gl->gl_waiters3)) {
+			gh = list_entry(gl->gl_waiters3.next,
+					struct gfs2_holder, gh_list);
+
+			if (test_bit(HIF_PROMOTE, &gh->gh_iflags))
+				blocked = rq_promote(gh);
+			else
+				gfs2_assert_warn(gl->gl_sbd, 0);
+
+		} else
+			break;
+
+		if (blocked)
+			break;
+	}
+}
+
+/**
+ * gfs2_glmutex_lock - acquire a local lock on a glock
+ * @gl: the glock
+ *
+ * Gives caller exclusive access to manipulate a glock structure.
+ */
+
+static void gfs2_glmutex_lock(struct gfs2_glock *gl)
+{
+	struct gfs2_holder gh;
+
+	gfs2_holder_init(gl, 0, 0, &gh);
+	set_bit(HIF_MUTEX, &gh.gh_iflags);
+
+	spin_lock(&gl->gl_spin);
+	if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
+		list_add_tail(&gh.gh_list, &gl->gl_waiters1);
+	} else {
+		gl->gl_owner = current;
+		gl->gl_ip = (unsigned long)__builtin_return_address(0);
+		complete(&gh.gh_wait);
+	}
+	spin_unlock(&gl->gl_spin);
+
+	wait_for_completion(&gh.gh_wait);
+	gfs2_holder_uninit(&gh);
+}
+
+/**
+ * gfs2_glmutex_trylock - try to acquire a local lock on a glock
+ * @gl: the glock
+ *
+ * Returns: 1 if the glock is acquired
+ */
+
+static int gfs2_glmutex_trylock(struct gfs2_glock *gl)
+{
+	int acquired = 1;
+
+	spin_lock(&gl->gl_spin);
+	if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
+		acquired = 0;
+	} else {
+		gl->gl_owner = current;
+		gl->gl_ip = (unsigned long)__builtin_return_address(0);
+	}
+	spin_unlock(&gl->gl_spin);
+
+	return acquired;
+}
+
+/**
+ * gfs2_glmutex_unlock - release a local lock on a glock
+ * @gl: the glock
+ *
+ */
+
+static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
+{
+	spin_lock(&gl->gl_spin);
+	clear_bit(GLF_LOCK, &gl->gl_flags);
+	gl->gl_owner = NULL;
+	gl->gl_ip = 0;
+	run_queue(gl);
+	BUG_ON(!spin_is_locked(&gl->gl_spin));
+	spin_unlock(&gl->gl_spin);
+}
+
+/**
+ * handle_callback - add a demote request to a lock's queue
+ * @gl: the glock
+ * @state: the state the caller wants us to change to
+ *
+ * Note: This may fail sliently if we are out of memory.
+ */
+
+static void handle_callback(struct gfs2_glock *gl, unsigned int state)
+{
+	struct gfs2_holder *gh, *new_gh = NULL;
+
+restart:
+	spin_lock(&gl->gl_spin);
+
+	list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
+		if (test_bit(HIF_DEMOTE, &gh->gh_iflags) &&
+		    gl->gl_req_gh != gh) {
+			if (gh->gh_state != state)
+				gh->gh_state = LM_ST_UNLOCKED;
+			goto out;
+		}
+	}
+
+	if (new_gh) {
+		list_add_tail(&new_gh->gh_list, &gl->gl_waiters2);
+		new_gh = NULL;
+	} else {
+		spin_unlock(&gl->gl_spin);
+
+		new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, GFP_KERNEL);
+		if (!new_gh)
+			return;
+		set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
+		set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
+
+		goto restart;
+	}
+
+out:
+	spin_unlock(&gl->gl_spin);
+
+	if (new_gh)
+		gfs2_holder_put(new_gh);
+}
+
+void gfs2_glock_inode_squish(struct inode *inode)
+{
+	struct gfs2_holder gh;
+	struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
+	gfs2_holder_init(gl, LM_ST_UNLOCKED, 0, &gh);
+	set_bit(HIF_DEMOTE, &gh.gh_iflags);
+	spin_lock(&gl->gl_spin);
+	gfs2_assert(inode->i_sb->s_fs_info, list_empty(&gl->gl_holders));
+	list_add_tail(&gh.gh_list, &gl->gl_waiters2);
+	run_queue(gl);
+	spin_unlock(&gl->gl_spin);
+	wait_for_completion(&gh.gh_wait);
+	gfs2_holder_uninit(&gh);
+}
+
+/**
+ * state_change - record that the glock is now in a different state
+ * @gl: the glock
+ * @new_state the new state
+ *
+ */
+
+static void state_change(struct gfs2_glock *gl, unsigned int new_state)
+{
+	int held1, held2;
+
+	held1 = (gl->gl_state != LM_ST_UNLOCKED);
+	held2 = (new_state != LM_ST_UNLOCKED);
+
+	if (held1 != held2) {
+		if (held2)
+			gfs2_glock_hold(gl);
+		else
+			gfs2_glock_put(gl);
+	}
+
+	gl->gl_state = new_state;
+}
+
+/**
+ * xmote_bh - Called after the lock module is done acquiring a lock
+ * @gl: The glock in question
+ * @ret: the int returned from the lock module
+ *
+ */
+
+static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+	struct gfs2_holder *gh = gl->gl_req_gh;
+	int prev_state = gl->gl_state;
+	int op_done = 1;
+
+	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+	gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC));
+
+	state_change(gl, ret & LM_OUT_ST_MASK);
+
+	if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) {
+		if (glops->go_inval)
+			glops->go_inval(gl, DIO_METADATA | DIO_DATA);
+	} else if (gl->gl_state == LM_ST_DEFERRED) {
+		/* We might not want to do this here.
+		   Look at moving to the inode glops. */
+		if (glops->go_inval)
+			glops->go_inval(gl, DIO_DATA);
+	}
+
+	/*  Deal with each possible exit condition  */
+
+	if (!gh)
+		gl->gl_stamp = jiffies;
+	else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+		spin_lock(&gl->gl_spin);
+		list_del_init(&gh->gh_list);
+		gh->gh_error = -EIO;
+		spin_unlock(&gl->gl_spin);
+	} else if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) {
+		spin_lock(&gl->gl_spin);
+		list_del_init(&gh->gh_list);
+		if (gl->gl_state == gh->gh_state ||
+		    gl->gl_state == LM_ST_UNLOCKED) {
+			gh->gh_error = 0;
+		} else {
+			if (gfs2_assert_warn(sdp, gh->gh_flags &
+					(LM_FLAG_TRY | LM_FLAG_TRY_1CB)) == -1)
+				fs_warn(sdp, "ret = 0x%.8X\n", ret);
+			gh->gh_error = GLR_TRYFAILED;
+		}
+		spin_unlock(&gl->gl_spin);
+
+		if (ret & LM_OUT_CANCELED)
+			handle_callback(gl, LM_ST_UNLOCKED);
+
+	} else if (ret & LM_OUT_CANCELED) {
+		spin_lock(&gl->gl_spin);
+		list_del_init(&gh->gh_list);
+		gh->gh_error = GLR_CANCELED;
+		spin_unlock(&gl->gl_spin);
+
+	} else if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
+		spin_lock(&gl->gl_spin);
+		list_move_tail(&gh->gh_list, &gl->gl_holders);
+		gh->gh_error = 0;
+		set_bit(HIF_HOLDER, &gh->gh_iflags);
+		spin_unlock(&gl->gl_spin);
+
+		set_bit(HIF_FIRST, &gh->gh_iflags);
+
+		op_done = 0;
+
+	} else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
+		spin_lock(&gl->gl_spin);
+		list_del_init(&gh->gh_list);
+		gh->gh_error = GLR_TRYFAILED;
+		spin_unlock(&gl->gl_spin);
+
+	} else {
+		if (gfs2_assert_withdraw(sdp, 0) == -1)
+			fs_err(sdp, "ret = 0x%.8X\n", ret);
+	}
+
+	if (glops->go_xmote_bh)
+		glops->go_xmote_bh(gl);
+
+	if (op_done) {
+		spin_lock(&gl->gl_spin);
+		gl->gl_req_gh = NULL;
+		gl->gl_req_bh = NULL;
+		clear_bit(GLF_LOCK, &gl->gl_flags);
+		run_queue(gl);
+		spin_unlock(&gl->gl_spin);
+	}
+
+	gfs2_glock_put(gl);
+
+	if (gh) {
+		if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
+			gfs2_holder_put(gh);
+		else
+			complete(&gh->gh_wait);
+	}
+}
+
+/**
+ * gfs2_glock_xmote_th - Call into the lock module to acquire or change a glock
+ * @gl: The glock in question
+ * @state: the requested state
+ * @flags: modifier flags to the lock call
+ *
+ */
+
+void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+	int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB |
+				 LM_FLAG_NOEXP | LM_FLAG_ANY |
+				 LM_FLAG_PRIORITY);
+	unsigned int lck_ret;
+
+	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+	gfs2_assert_warn(sdp, state != LM_ST_UNLOCKED);
+	gfs2_assert_warn(sdp, state != gl->gl_state);
+
+	if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
+		glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE);
+
+	gfs2_glock_hold(gl);
+	gl->gl_req_bh = xmote_bh;
+
+	lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, lck_flags);
+
+	if (gfs2_assert_withdraw(sdp, !(lck_ret & LM_OUT_ERROR)))
+		return;
+
+	if (lck_ret & LM_OUT_ASYNC)
+		gfs2_assert_warn(sdp, lck_ret == LM_OUT_ASYNC);
+	else
+		xmote_bh(gl, lck_ret);
+}
+
+/**
+ * drop_bh - Called after a lock module unlock completes
+ * @gl: the glock
+ * @ret: the return status
+ *
+ * Doesn't wake up the process waiting on the struct gfs2_holder (if any)
+ * Doesn't drop the reference on the glock the top half took out
+ *
+ */
+
+static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+	struct gfs2_holder *gh = gl->gl_req_gh;
+
+	clear_bit(GLF_PREFETCH, &gl->gl_flags);
+
+	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+	gfs2_assert_warn(sdp, !ret);
+
+	state_change(gl, LM_ST_UNLOCKED);
+
+	if (glops->go_inval)
+		glops->go_inval(gl, DIO_METADATA | DIO_DATA);
+
+	if (gh) {
+		spin_lock(&gl->gl_spin);
+		list_del_init(&gh->gh_list);
+		gh->gh_error = 0;
+		spin_unlock(&gl->gl_spin);
+	}
+
+	if (glops->go_drop_bh)
+		glops->go_drop_bh(gl);
+
+	spin_lock(&gl->gl_spin);
+	gl->gl_req_gh = NULL;
+	gl->gl_req_bh = NULL;
+	clear_bit(GLF_LOCK, &gl->gl_flags);
+	run_queue(gl);
+	spin_unlock(&gl->gl_spin);
+
+	gfs2_glock_put(gl);
+
+	if (gh) {
+		if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
+			gfs2_holder_put(gh);
+		else
+			complete(&gh->gh_wait);
+	}
+}
+
+/**
+ * gfs2_glock_drop_th - call into the lock module to unlock a lock
+ * @gl: the glock
+ *
+ */
+
+void gfs2_glock_drop_th(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+	unsigned int ret;
+
+	gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+	gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+	gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED);
+
+	if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
+		glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE);
+
+	gfs2_glock_hold(gl);
+	gl->gl_req_bh = drop_bh;
+
+	ret = gfs2_lm_unlock(sdp, gl->gl_lock, gl->gl_state);
+
+	if (gfs2_assert_withdraw(sdp, !(ret & LM_OUT_ERROR)))
+		return;
+
+	if (!ret)
+		drop_bh(gl, ret);
+	else
+		gfs2_assert_warn(sdp, ret == LM_OUT_ASYNC);
+}
+
+/**
+ * do_cancels - cancel requests for locks stuck waiting on an expire flag
+ * @gh: the LM_FLAG_PRIORITY holder waiting to acquire the lock
+ *
+ * Don't cancel GL_NOCANCEL requests.
+ */
+
+static void do_cancels(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+
+	spin_lock(&gl->gl_spin);
+
+	while (gl->gl_req_gh != gh &&
+	       !test_bit(HIF_HOLDER, &gh->gh_iflags) &&
+	       !list_empty(&gh->gh_list)) {
+		if (gl->gl_req_bh && !(gl->gl_req_gh &&
+				     (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) {
+			spin_unlock(&gl->gl_spin);
+			gfs2_lm_cancel(gl->gl_sbd, gl->gl_lock);
+			msleep(100);
+			spin_lock(&gl->gl_spin);
+		} else {
+			spin_unlock(&gl->gl_spin);
+			msleep(100);
+			spin_lock(&gl->gl_spin);
+		}
+	}
+
+	spin_unlock(&gl->gl_spin);
+}
+
+/**
+ * glock_wait_internal - wait on a glock acquisition
+ * @gh: the glock holder
+ *
+ * Returns: 0 on success
+ */
+
+static int glock_wait_internal(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+	if (test_bit(HIF_ABORTED, &gh->gh_iflags))
+		return -EIO;
+
+	if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
+		spin_lock(&gl->gl_spin);
+		if (gl->gl_req_gh != gh &&
+		    !test_bit(HIF_HOLDER, &gh->gh_iflags) &&
+		    !list_empty(&gh->gh_list)) {
+			list_del_init(&gh->gh_list);
+			gh->gh_error = GLR_TRYFAILED;
+			run_queue(gl);
+			spin_unlock(&gl->gl_spin);
+			return gh->gh_error;
+		}
+		spin_unlock(&gl->gl_spin);
+	}
+
+	if (gh->gh_flags & LM_FLAG_PRIORITY)
+		do_cancels(gh);
+
+	wait_for_completion(&gh->gh_wait);
+
+	if (gh->gh_error)
+		return gh->gh_error;
+
+	gfs2_assert_withdraw(sdp, test_bit(HIF_HOLDER, &gh->gh_iflags));
+	gfs2_assert_withdraw(sdp, relaxed_state_ok(gl->gl_state, gh->gh_state,
+						   gh->gh_flags));
+
+	if (test_bit(HIF_FIRST, &gh->gh_iflags)) {
+		gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+
+		if (glops->go_lock) {
+			gh->gh_error = glops->go_lock(gh);
+			if (gh->gh_error) {
+				spin_lock(&gl->gl_spin);
+				list_del_init(&gh->gh_list);
+				spin_unlock(&gl->gl_spin);
+			}
+		}
+
+		spin_lock(&gl->gl_spin);
+		gl->gl_req_gh = NULL;
+		gl->gl_req_bh = NULL;
+		clear_bit(GLF_LOCK, &gl->gl_flags);
+		run_queue(gl);
+		spin_unlock(&gl->gl_spin);
+	}
+
+	return gh->gh_error;
+}
+
+static inline struct gfs2_holder *
+find_holder_by_owner(struct list_head *head, struct task_struct *owner)
+{
+	struct gfs2_holder *gh;
+
+	list_for_each_entry(gh, head, gh_list) {
+		if (gh->gh_owner == owner)
+			return gh;
+	}
+
+	return NULL;
+}
+
+/**
+ * add_to_queue - Add a holder to the wait queue (but look for recursion)
+ * @gh: the holder structure to add
+ *
+ */
+
+static void add_to_queue(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	struct gfs2_holder *existing;
+
+	BUG_ON(!gh->gh_owner);
+
+	existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
+	if (existing) {
+		print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
+		printk(KERN_INFO "pid : %d\n", existing->gh_owner->pid);
+		printk(KERN_INFO "lock type : %d lock state : %d\n",
+				existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
+		print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+		printk(KERN_INFO "pid : %d\n", gh->gh_owner->pid);
+		printk(KERN_INFO "lock type : %d lock state : %d\n",
+				gl->gl_name.ln_type, gl->gl_state);
+		BUG();
+	}
+
+	existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner);
+	if (existing) {
+		print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
+		print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+		BUG();
+	}
+
+	if (gh->gh_flags & LM_FLAG_PRIORITY)
+		list_add(&gh->gh_list, &gl->gl_waiters3);
+	else
+		list_add_tail(&gh->gh_list, &gl->gl_waiters3);
+}
+
+/**
+ * gfs2_glock_nq - enqueue a struct gfs2_holder onto a glock (acquire a glock)
+ * @gh: the holder structure
+ *
+ * if (gh->gh_flags & GL_ASYNC), this never returns an error
+ *
+ * Returns: 0, GLR_TRYFAILED, or errno on failure
+ */
+
+int gfs2_glock_nq(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	int error = 0;
+
+restart:
+	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+		set_bit(HIF_ABORTED, &gh->gh_iflags);
+		return -EIO;
+	}
+
+	set_bit(HIF_PROMOTE, &gh->gh_iflags);
+
+	spin_lock(&gl->gl_spin);
+	add_to_queue(gh);
+	run_queue(gl);
+	spin_unlock(&gl->gl_spin);
+
+	if (!(gh->gh_flags & GL_ASYNC)) {
+		error = glock_wait_internal(gh);
+		if (error == GLR_CANCELED) {
+			msleep(100);
+			goto restart;
+		}
+	}
+
+	clear_bit(GLF_PREFETCH, &gl->gl_flags);
+
+	if (error == GLR_TRYFAILED && (gh->gh_flags & GL_DUMP))
+		dump_glock(gl);
+
+	return error;
+}
+
+/**
+ * gfs2_glock_poll - poll to see if an async request has been completed
+ * @gh: the holder
+ *
+ * Returns: 1 if the request is ready to be gfs2_glock_wait()ed on
+ */
+
+int gfs2_glock_poll(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	int ready = 0;
+
+	spin_lock(&gl->gl_spin);
+
+	if (test_bit(HIF_HOLDER, &gh->gh_iflags))
+		ready = 1;
+	else if (list_empty(&gh->gh_list)) {
+		if (gh->gh_error == GLR_CANCELED) {
+			spin_unlock(&gl->gl_spin);
+			msleep(100);
+			if (gfs2_glock_nq(gh))
+				return 1;
+			return 0;
+		} else
+			ready = 1;
+	}
+
+	spin_unlock(&gl->gl_spin);
+
+	return ready;
+}
+
+/**
+ * gfs2_glock_wait - wait for a lock acquisition that ended in a GLR_ASYNC
+ * @gh: the holder structure
+ *
+ * Returns: 0, GLR_TRYFAILED, or errno on failure
+ */
+
+int gfs2_glock_wait(struct gfs2_holder *gh)
+{
+	int error;
+
+	error = glock_wait_internal(gh);
+	if (error == GLR_CANCELED) {
+		msleep(100);
+		gh->gh_flags &= ~GL_ASYNC;
+		error = gfs2_glock_nq(gh);
+	}
+
+	return error;
+}
+
+/**
+ * gfs2_glock_dq - dequeue a struct gfs2_holder from a glock (release a glock)
+ * @gh: the glock holder
+ *
+ */
+
+void gfs2_glock_dq(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+	if (gh->gh_flags & GL_NOCACHE)
+		handle_callback(gl, LM_ST_UNLOCKED);
+
+	gfs2_glmutex_lock(gl);
+
+	spin_lock(&gl->gl_spin);
+	list_del_init(&gh->gh_list);
+
+	if (list_empty(&gl->gl_holders)) {
+		spin_unlock(&gl->gl_spin);
+
+		if (glops->go_unlock)
+			glops->go_unlock(gh);
+
+		gl->gl_stamp = jiffies;
+
+		spin_lock(&gl->gl_spin);
+	}
+
+	clear_bit(GLF_LOCK, &gl->gl_flags);
+	run_queue(gl);
+	spin_unlock(&gl->gl_spin);
+}
+
+/**
+ * gfs2_glock_prefetch - Try to prefetch a glock
+ * @gl: the glock
+ * @state: the state to prefetch in
+ * @flags: flags passed to go_xmote_th()
+ *
+ */
+
+static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state,
+				int flags)
+{
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+	spin_lock(&gl->gl_spin);
+
+	if (test_bit(GLF_LOCK, &gl->gl_flags) || !list_empty(&gl->gl_holders) ||
+	    !list_empty(&gl->gl_waiters1) || !list_empty(&gl->gl_waiters2) ||
+	    !list_empty(&gl->gl_waiters3) ||
+	    relaxed_state_ok(gl->gl_state, state, flags)) {
+		spin_unlock(&gl->gl_spin);
+		return;
+	}
+
+	set_bit(GLF_PREFETCH, &gl->gl_flags);
+	set_bit(GLF_LOCK, &gl->gl_flags);
+	spin_unlock(&gl->gl_spin);
+
+	glops->go_xmote_th(gl, state, flags);
+}
+
+static void greedy_work(void *data)
+{
+	struct greedy *gr = data;
+	struct gfs2_holder *gh = &gr->gr_gh;
+	struct gfs2_glock *gl = gh->gh_gl;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+	clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
+
+	if (glops->go_greedy)
+		glops->go_greedy(gl);
+
+	spin_lock(&gl->gl_spin);
+
+	if (list_empty(&gl->gl_waiters2)) {
+		clear_bit(GLF_GREEDY, &gl->gl_flags);
+		spin_unlock(&gl->gl_spin);
+		gfs2_holder_uninit(gh);
+		kfree(gr);
+	} else {
+		gfs2_glock_hold(gl);
+		list_add_tail(&gh->gh_list, &gl->gl_waiters2);
+		run_queue(gl);
+		spin_unlock(&gl->gl_spin);
+		gfs2_glock_put(gl);
+	}
+}
+
+/**
+ * gfs2_glock_be_greedy -
+ * @gl:
+ * @time:
+ *
+ * Returns: 0 if go_greedy will be called, 1 otherwise
+ */
+
+int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time)
+{
+	struct greedy *gr;
+	struct gfs2_holder *gh;
+
+	if (!time || gl->gl_sbd->sd_args.ar_localcaching ||
+	    test_and_set_bit(GLF_GREEDY, &gl->gl_flags))
+		return 1;
+
+	gr = kmalloc(sizeof(struct greedy), GFP_KERNEL);
+	if (!gr) {
+		clear_bit(GLF_GREEDY, &gl->gl_flags);
+		return 1;
+	}
+	gh = &gr->gr_gh;
+
+	gfs2_holder_init(gl, 0, 0, gh);
+	set_bit(HIF_GREEDY, &gh->gh_iflags);
+	INIT_WORK(&gr->gr_work, greedy_work, gr);
+
+	set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
+	schedule_delayed_work(&gr->gr_work, time);
+
+	return 0;
+}
+
+/**
+ * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it
+ * @gh: the holder structure
+ *
+ */
+
+void gfs2_glock_dq_uninit(struct gfs2_holder *gh)
+{
+	gfs2_glock_dq(gh);
+	gfs2_holder_uninit(gh);
+}
+
+/**
+ * gfs2_glock_nq_num - acquire a glock based on lock number
+ * @sdp: the filesystem
+ * @number: the lock number
+ * @glops: the glock operations for the type of glock
+ * @state: the state to acquire the glock in
+ * @flags: modifier flags for the aquisition
+ * @gh: the struct gfs2_holder
+ *
+ * Returns: errno
+ */
+
+int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number,
+		      const struct gfs2_glock_operations *glops,
+		      unsigned int state, int flags, struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl;
+	int error;
+
+	error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
+	if (!error) {
+		error = gfs2_glock_nq_init(gl, state, flags, gh);
+		gfs2_glock_put(gl);
+	}
+
+	return error;
+}
+
+/**
+ * glock_compare - Compare two struct gfs2_glock structures for sorting
+ * @arg_a: the first structure
+ * @arg_b: the second structure
+ *
+ */
+
+static int glock_compare(const void *arg_a, const void *arg_b)
+{
+	const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a;
+	const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b;
+	const struct lm_lockname *a = &gh_a->gh_gl->gl_name;
+	const struct lm_lockname *b = &gh_b->gh_gl->gl_name;
+
+	if (a->ln_number > b->ln_number)
+		return 1;
+	if (a->ln_number < b->ln_number)
+		return -1;
+	if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
+		return 1;
+	if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && (gh_b->gh_flags & GL_LOCAL_EXCL))
+		return 1;
+	return 0;
+}
+
+/**
+ * nq_m_sync - synchonously acquire more than one glock in deadlock free order
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ * Returns: 0 on success (all glocks acquired),
+ *          errno on failure (no glocks acquired)
+ */
+
+static int nq_m_sync(unsigned int num_gh, struct gfs2_holder *ghs,
+		     struct gfs2_holder **p)
+{
+	unsigned int x;
+	int error = 0;
+
+	for (x = 0; x < num_gh; x++)
+		p[x] = &ghs[x];
+
+	sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare, NULL);
+
+	for (x = 0; x < num_gh; x++) {
+		p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+
+		error = gfs2_glock_nq(p[x]);
+		if (error) {
+			while (x--)
+				gfs2_glock_dq(p[x]);
+			break;
+		}
+	}
+
+	return error;
+}
+
+/**
+ * gfs2_glock_nq_m - acquire multiple glocks
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ * Figure out how big an impact this function has.  Either:
+ * 1) Replace this code with code that calls gfs2_glock_prefetch()
+ * 2) Forget async stuff and just call nq_m_sync()
+ * 3) Leave it like it is
+ *
+ * Returns: 0 on success (all glocks acquired),
+ *          errno on failure (no glocks acquired)
+ */
+
+int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+	int *e;
+	unsigned int x;
+	int borked = 0, serious = 0;
+	int error = 0;
+
+	if (!num_gh)
+		return 0;
+
+	if (num_gh == 1) {
+		ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+		return gfs2_glock_nq(ghs);
+	}
+
+	e = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
+	if (!e)
+		return -ENOMEM;
+
+	for (x = 0; x < num_gh; x++) {
+		ghs[x].gh_flags |= LM_FLAG_TRY | GL_ASYNC;
+		error = gfs2_glock_nq(&ghs[x]);
+		if (error) {
+			borked = 1;
+			serious = error;
+			num_gh = x;
+			break;
+		}
+	}
+
+	for (x = 0; x < num_gh; x++) {
+		error = e[x] = glock_wait_internal(&ghs[x]);
+		if (error) {
+			borked = 1;
+			if (error != GLR_TRYFAILED && error != GLR_CANCELED)
+				serious = error;
+		}
+	}
+
+	if (!borked) {
+		kfree(e);
+		return 0;
+	}
+
+	for (x = 0; x < num_gh; x++)
+		if (!e[x])
+			gfs2_glock_dq(&ghs[x]);
+
+	if (serious)
+		error = serious;
+	else {
+		for (x = 0; x < num_gh; x++)
+			gfs2_holder_reinit(ghs[x].gh_state, ghs[x].gh_flags,
+					  &ghs[x]);
+		error = nq_m_sync(num_gh, ghs, (struct gfs2_holder **)e);
+	}
+
+	kfree(e);
+
+	return error;
+}
+
+/**
+ * gfs2_glock_dq_m - release multiple glocks
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ */
+
+void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+	unsigned int x;
+
+	for (x = 0; x < num_gh; x++)
+		gfs2_glock_dq(&ghs[x]);
+}
+
+/**
+ * gfs2_glock_dq_uninit_m - release multiple glocks
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ */
+
+void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+	unsigned int x;
+
+	for (x = 0; x < num_gh; x++)
+		gfs2_glock_dq_uninit(&ghs[x]);
+}
+
+/**
+ * gfs2_glock_prefetch_num - prefetch a glock based on lock number
+ * @sdp: the filesystem
+ * @number: the lock number
+ * @glops: the glock operations for the type of glock
+ * @state: the state to acquire the glock in
+ * @flags: modifier flags for the aquisition
+ *
+ * Returns: errno
+ */
+
+void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
+			     const struct gfs2_glock_operations *glops,
+			     unsigned int state, int flags)
+{
+	struct gfs2_glock *gl;
+	int error;
+
+	if (atomic_read(&sdp->sd_reclaim_count) <
+	    gfs2_tune_get(sdp, gt_reclaim_limit)) {
+		error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
+		if (!error) {
+			gfs2_glock_prefetch(gl, state, flags);
+			gfs2_glock_put(gl);
+		}
+	}
+}
+
+/**
+ * gfs2_lvb_hold - attach a LVB from a glock
+ * @gl: The glock in question
+ *
+ */
+
+int gfs2_lvb_hold(struct gfs2_glock *gl)
+{
+	int error;
+
+	gfs2_glmutex_lock(gl);
+
+	if (!atomic_read(&gl->gl_lvb_count)) {
+		error = gfs2_lm_hold_lvb(gl->gl_sbd, gl->gl_lock, &gl->gl_lvb);
+		if (error) {
+			gfs2_glmutex_unlock(gl);
+			return error;
+		}
+		gfs2_glock_hold(gl);
+	}
+	atomic_inc(&gl->gl_lvb_count);
+
+	gfs2_glmutex_unlock(gl);
+
+	return 0;
+}
+
+/**
+ * gfs2_lvb_unhold - detach a LVB from a glock
+ * @gl: The glock in question
+ *
+ */
+
+void gfs2_lvb_unhold(struct gfs2_glock *gl)
+{
+	gfs2_glock_hold(gl);
+	gfs2_glmutex_lock(gl);
+
+	gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0);
+	if (atomic_dec_and_test(&gl->gl_lvb_count)) {
+		gfs2_lm_unhold_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb);
+		gl->gl_lvb = NULL;
+		gfs2_glock_put(gl);
+	}
+
+	gfs2_glmutex_unlock(gl);
+	gfs2_glock_put(gl);
+}
+
+static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
+			unsigned int state)
+{
+	struct gfs2_glock *gl;
+
+	gl = gfs2_glock_find(sdp, name);
+	if (!gl)
+		return;
+
+	if (gl->gl_ops->go_callback)
+		gl->gl_ops->go_callback(gl, state);
+	handle_callback(gl, state);
+
+	spin_lock(&gl->gl_spin);
+	run_queue(gl);
+	spin_unlock(&gl->gl_spin);
+
+	gfs2_glock_put(gl);
+}
+
+/**
+ * gfs2_glock_cb - Callback used by locking module
+ * @sdp: Pointer to the superblock
+ * @type: Type of callback
+ * @data: Type dependent data pointer
+ *
+ * Called by the locking module when it wants to tell us something.
+ * Either we need to drop a lock, one of our ASYNC requests completed, or
+ * a journal from another client needs to be recovered.
+ */
+
+void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
+{
+	struct gfs2_sbd *sdp = cb_data;
+
+	switch (type) {
+	case LM_CB_NEED_E:
+		blocking_cb(sdp, data, LM_ST_UNLOCKED);
+		return;
+
+	case LM_CB_NEED_D:
+		blocking_cb(sdp, data, LM_ST_DEFERRED);
+		return;
+
+	case LM_CB_NEED_S:
+		blocking_cb(sdp, data, LM_ST_SHARED);
+		return;
+
+	case LM_CB_ASYNC: {
+		struct lm_async_cb *async = data;
+		struct gfs2_glock *gl;
+
+		gl = gfs2_glock_find(sdp, &async->lc_name);
+		if (gfs2_assert_warn(sdp, gl))
+			return;
+		if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
+			gl->gl_req_bh(gl, async->lc_ret);
+		gfs2_glock_put(gl);
+		return;
+	}
+
+	case LM_CB_NEED_RECOVERY:
+		gfs2_jdesc_make_dirty(sdp, *(unsigned int *)data);
+		if (sdp->sd_recoverd_process)
+			wake_up_process(sdp->sd_recoverd_process);
+		return;
+
+	case LM_CB_DROPLOCKS:
+		gfs2_gl_hash_clear(sdp, NO_WAIT);
+		gfs2_quota_scan(sdp);
+		return;
+
+	default:
+		gfs2_assert_warn(sdp, 0);
+		return;
+	}
+}
+
+/**
+ * demote_ok - Check to see if it's ok to unlock a glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int demote_ok(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	const struct gfs2_glock_operations *glops = gl->gl_ops;
+	int demote = 1;
+
+	if (test_bit(GLF_STICKY, &gl->gl_flags))
+		demote = 0;
+	else if (test_bit(GLF_PREFETCH, &gl->gl_flags))
+		demote = time_after_eq(jiffies, gl->gl_stamp +
+				    gfs2_tune_get(sdp, gt_prefetch_secs) * HZ);
+	else if (glops->go_demote_ok)
+		demote = glops->go_demote_ok(gl);
+
+	return demote;
+}
+
+/**
+ * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list
+ * @gl: the glock
+ *
+ */
+
+void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+
+	spin_lock(&sdp->sd_reclaim_lock);
+	if (list_empty(&gl->gl_reclaim)) {
+		gfs2_glock_hold(gl);
+		list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list);
+		atomic_inc(&sdp->sd_reclaim_count);
+	}
+	spin_unlock(&sdp->sd_reclaim_lock);
+
+	wake_up(&sdp->sd_reclaim_wq);
+}
+
+/**
+ * gfs2_reclaim_glock - process the next glock on the filesystem's reclaim list
+ * @sdp: the filesystem
+ *
+ * Called from gfs2_glockd() glock reclaim daemon, or when promoting a
+ * different glock and we notice that there are a lot of glocks in the
+ * reclaim list.
+ *
+ */
+
+void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
+{
+	struct gfs2_glock *gl;
+
+	spin_lock(&sdp->sd_reclaim_lock);
+	if (list_empty(&sdp->sd_reclaim_list)) {
+		spin_unlock(&sdp->sd_reclaim_lock);
+		return;
+	}
+	gl = list_entry(sdp->sd_reclaim_list.next,
+			struct gfs2_glock, gl_reclaim);
+	list_del_init(&gl->gl_reclaim);
+	spin_unlock(&sdp->sd_reclaim_lock);
+
+	atomic_dec(&sdp->sd_reclaim_count);
+	atomic_inc(&sdp->sd_reclaimed);
+
+	if (gfs2_glmutex_trylock(gl)) {
+		if (queue_empty(gl, &gl->gl_holders) &&
+		    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
+			handle_callback(gl, LM_ST_UNLOCKED);
+		gfs2_glmutex_unlock(gl);
+	}
+
+	gfs2_glock_put(gl);
+}
+
+/**
+ * examine_bucket - Call a function for glock in a hash bucket
+ * @examiner: the function
+ * @sdp: the filesystem
+ * @bucket: the bucket
+ *
+ * Returns: 1 if the bucket has entries
+ */
+
+static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
+			  unsigned int hash)
+{
+	struct gfs2_glock *gl, *prev = NULL;
+	int has_entries = 0;
+	struct hlist_head *head = &gl_hash_table[hash].hb_list;
+
+	read_lock(gl_lock_addr(hash));
+	/* Can't use hlist_for_each_entry - don't want prefetch here */
+	if (hlist_empty(head))
+		goto out;
+	gl = list_entry(head->first, struct gfs2_glock, gl_list);
+	while(1) {
+		if (gl->gl_sbd == sdp) {
+			gfs2_glock_hold(gl);
+			read_unlock(gl_lock_addr(hash));
+			if (prev)
+				gfs2_glock_put(prev);
+			prev = gl;
+			examiner(gl);
+			has_entries = 1;
+			read_lock(gl_lock_addr(hash));
+		}
+		if (gl->gl_list.next == NULL)
+			break;
+		gl = list_entry(gl->gl_list.next, struct gfs2_glock, gl_list);
+	}
+out:
+	read_unlock(gl_lock_addr(hash));
+	if (prev)
+		gfs2_glock_put(prev);
+	return has_entries;
+}
+
+/**
+ * scan_glock - look at a glock and see if we can reclaim it
+ * @gl: the glock to look at
+ *
+ */
+
+static void scan_glock(struct gfs2_glock *gl)
+{
+	if (gl->gl_ops == &gfs2_inode_glops)
+		return;
+
+	if (gfs2_glmutex_trylock(gl)) {
+		if (queue_empty(gl, &gl->gl_holders) &&
+		    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
+			goto out_schedule;
+		gfs2_glmutex_unlock(gl);
+	}
+	return;
+
+out_schedule:
+	gfs2_glmutex_unlock(gl);
+	gfs2_glock_schedule_for_reclaim(gl);
+}
+
+/**
+ * gfs2_scand_internal - Look for glocks and inodes to toss from memory
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_scand_internal(struct gfs2_sbd *sdp)
+{
+	unsigned int x;
+
+	for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
+		examine_bucket(scan_glock, sdp, x);
+}
+
+/**
+ * clear_glock - look at a glock and see if we can free it from glock cache
+ * @gl: the glock to look at
+ *
+ */
+
+static void clear_glock(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	int released;
+
+	spin_lock(&sdp->sd_reclaim_lock);
+	if (!list_empty(&gl->gl_reclaim)) {
+		list_del_init(&gl->gl_reclaim);
+		atomic_dec(&sdp->sd_reclaim_count);
+		spin_unlock(&sdp->sd_reclaim_lock);
+		released = gfs2_glock_put(gl);
+		gfs2_assert(sdp, !released);
+	} else {
+		spin_unlock(&sdp->sd_reclaim_lock);
+	}
+
+	if (gfs2_glmutex_trylock(gl)) {
+		if (queue_empty(gl, &gl->gl_holders) &&
+		    gl->gl_state != LM_ST_UNLOCKED)
+			handle_callback(gl, LM_ST_UNLOCKED);
+		gfs2_glmutex_unlock(gl);
+	}
+}
+
+/**
+ * gfs2_gl_hash_clear - Empty out the glock hash table
+ * @sdp: the filesystem
+ * @wait: wait until it's all gone
+ *
+ * Called when unmounting the filesystem, or when inter-node lock manager
+ * requests DROPLOCKS because it is running out of capacity.
+ */
+
+void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
+{
+	unsigned long t;
+	unsigned int x;
+	int cont;
+
+	t = jiffies;
+
+	for (;;) {
+		cont = 0;
+		for (x = 0; x < GFS2_GL_HASH_SIZE; x++) {
+			if (examine_bucket(clear_glock, sdp, x))
+				cont = 1;
+		}
+
+		if (!wait || !cont)
+			break;
+
+		if (time_after_eq(jiffies,
+				  t + gfs2_tune_get(sdp, gt_stall_secs) * HZ)) {
+			fs_warn(sdp, "Unmount seems to be stalled. "
+				     "Dumping lock state...\n");
+			gfs2_dump_lockstate(sdp);
+			t = jiffies;
+		}
+
+		invalidate_inodes(sdp->sd_vfs);
+		msleep(10);
+	}
+}
+
+/*
+ *  Diagnostic routines to help debug distributed deadlock
+ */
+
+/**
+ * dump_holder - print information about a glock holder
+ * @str: a string naming the type of holder
+ * @gh: the glock holder
+ *
+ * Returns: 0 on success, -ENOBUFS when we run out of space
+ */
+
+static int dump_holder(char *str, struct gfs2_holder *gh)
+{
+	unsigned int x;
+	int error = -ENOBUFS;
+
+	printk(KERN_INFO "  %s\n", str);
+	printk(KERN_INFO "    owner = %ld\n",
+		   (gh->gh_owner) ? (long)gh->gh_owner->pid : -1);
+	printk(KERN_INFO "    gh_state = %u\n", gh->gh_state);
+	printk(KERN_INFO "    gh_flags =");
+	for (x = 0; x < 32; x++)
+		if (gh->gh_flags & (1 << x))
+			printk(" %u", x);
+	printk(" \n");
+	printk(KERN_INFO "    error = %d\n", gh->gh_error);
+	printk(KERN_INFO "    gh_iflags =");
+	for (x = 0; x < 32; x++)
+		if (test_bit(x, &gh->gh_iflags))
+			printk(" %u", x);
+	printk(" \n");
+	print_symbol(KERN_INFO "    initialized at: %s\n", gh->gh_ip);
+
+	error = 0;
+
+	return error;
+}
+
+/**
+ * dump_inode - print information about an inode
+ * @ip: the inode
+ *
+ * Returns: 0 on success, -ENOBUFS when we run out of space
+ */
+
+static int dump_inode(struct gfs2_inode *ip)
+{
+	unsigned int x;
+	int error = -ENOBUFS;
+
+	printk(KERN_INFO "  Inode:\n");
+	printk(KERN_INFO "    num = %llu %llu\n",
+		    (unsigned long long)ip->i_num.no_formal_ino,
+		    (unsigned long long)ip->i_num.no_addr);
+	printk(KERN_INFO "    type = %u\n", IF2DT(ip->i_di.di_mode));
+	printk(KERN_INFO "    i_flags =");
+	for (x = 0; x < 32; x++)
+		if (test_bit(x, &ip->i_flags))
+			printk(" %u", x);
+	printk(" \n");
+
+	error = 0;
+
+	return error;
+}
+
+/**
+ * dump_glock - print information about a glock
+ * @gl: the glock
+ * @count: where we are in the buffer
+ *
+ * Returns: 0 on success, -ENOBUFS when we run out of space
+ */
+
+static int dump_glock(struct gfs2_glock *gl)
+{
+	struct gfs2_holder *gh;
+	unsigned int x;
+	int error = -ENOBUFS;
+
+	spin_lock(&gl->gl_spin);
+
+	printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+	       (unsigned long long)gl->gl_name.ln_number);
+	printk(KERN_INFO "  gl_flags =");
+	for (x = 0; x < 32; x++) {
+		if (test_bit(x, &gl->gl_flags))
+			printk(" %u", x);
+	}
+	printk(" \n");
+	printk(KERN_INFO "  gl_ref = %d\n", atomic_read(&gl->gl_ref));
+	printk(KERN_INFO "  gl_state = %u\n", gl->gl_state);
+	printk(KERN_INFO "  gl_owner = %s\n", gl->gl_owner->comm);
+	print_symbol(KERN_INFO "  gl_ip = %s\n", gl->gl_ip);
+	printk(KERN_INFO "  req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
+	printk(KERN_INFO "  req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
+	printk(KERN_INFO "  lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
+	printk(KERN_INFO "  object = %s\n", (gl->gl_object) ? "yes" : "no");
+	printk(KERN_INFO "  le = %s\n",
+		   (list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
+	printk(KERN_INFO "  reclaim = %s\n",
+		    (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
+	if (gl->gl_aspace)
+		printk(KERN_INFO "  aspace = 0x%p nrpages = %lu\n", gl->gl_aspace,
+		       gl->gl_aspace->i_mapping->nrpages);
+	else
+		printk(KERN_INFO "  aspace = no\n");
+	printk(KERN_INFO "  ail = %d\n", atomic_read(&gl->gl_ail_count));
+	if (gl->gl_req_gh) {
+		error = dump_holder("Request", gl->gl_req_gh);
+		if (error)
+			goto out;
+	}
+	list_for_each_entry(gh, &gl->gl_holders, gh_list) {
+		error = dump_holder("Holder", gh);
+		if (error)
+			goto out;
+	}
+	list_for_each_entry(gh, &gl->gl_waiters1, gh_list) {
+		error = dump_holder("Waiter1", gh);
+		if (error)
+			goto out;
+	}
+	list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
+		error = dump_holder("Waiter2", gh);
+		if (error)
+			goto out;
+	}
+	list_for_each_entry(gh, &gl->gl_waiters3, gh_list) {
+		error = dump_holder("Waiter3", gh);
+		if (error)
+			goto out;
+	}
+	if (gl->gl_ops == &gfs2_inode_glops && gl->gl_object) {
+		if (!test_bit(GLF_LOCK, &gl->gl_flags) &&
+		    list_empty(&gl->gl_holders)) {
+			error = dump_inode(gl->gl_object);
+			if (error)
+				goto out;
+		} else {
+			error = -ENOBUFS;
+			printk(KERN_INFO "  Inode: busy\n");
+		}
+	}
+
+	error = 0;
+
+out:
+	spin_unlock(&gl->gl_spin);
+	return error;
+}
+
+/**
+ * gfs2_dump_lockstate - print out the current lockstate
+ * @sdp: the filesystem
+ * @ub: the buffer to copy the information into
+ *
+ * If @ub is NULL, dump the lockstate to the console.
+ *
+ */
+
+static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
+{
+	struct gfs2_glock *gl;
+	struct hlist_node *h;
+	unsigned int x;
+	int error = 0;
+
+	for (x = 0; x < GFS2_GL_HASH_SIZE; x++) {
+
+		read_lock(gl_lock_addr(x));
+
+		hlist_for_each_entry(gl, h, &gl_hash_table[x].hb_list, gl_list) {
+			if (gl->gl_sbd != sdp)
+				continue;
+
+			error = dump_glock(gl);
+			if (error)
+				break;
+		}
+
+		read_unlock(gl_lock_addr(x));
+
+		if (error)
+			break;
+	}
+
+
+	return error;
+}
+
+int __init gfs2_glock_init(void)
+{
+	unsigned i;
+	for(i = 0; i < GFS2_GL_HASH_SIZE; i++) {
+		INIT_HLIST_HEAD(&gl_hash_table[i].hb_list);
+	}
+#ifdef GL_HASH_LOCK_SZ
+	for(i = 0; i < GL_HASH_LOCK_SZ; i++) {
+		rwlock_init(&gl_hash_locks[i]);
+	}
+#endif
+	return 0;
+}
+
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
new file mode 100644
index 0000000..2b2a889
--- /dev/null
+++ b/fs/gfs2/glock.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __GLOCK_DOT_H__
+#define __GLOCK_DOT_H__
+
+#include "incore.h"
+
+/* Flags for lock requests; used in gfs2_holder gh_flag field.
+   From lm_interface.h:
+#define LM_FLAG_TRY		0x00000001
+#define LM_FLAG_TRY_1CB		0x00000002
+#define LM_FLAG_NOEXP		0x00000004
+#define LM_FLAG_ANY		0x00000008
+#define LM_FLAG_PRIORITY	0x00000010 */
+
+#define GL_LOCAL_EXCL		0x00000020
+#define GL_ASYNC		0x00000040
+#define GL_EXACT		0x00000080
+#define GL_SKIP			0x00000100
+#define GL_ATIME		0x00000200
+#define GL_NOCACHE		0x00000400
+#define GL_NOCANCEL		0x00001000
+#define GL_AOP			0x00004000
+#define GL_DUMP			0x00008000
+
+#define GLR_TRYFAILED		13
+#define GLR_CANCELED		14
+
+static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
+{
+	struct gfs2_holder *gh;
+	int locked = 0;
+
+	/* Look in glock's list of holders for one with current task as owner */
+	spin_lock(&gl->gl_spin);
+	list_for_each_entry(gh, &gl->gl_holders, gh_list) {
+		if (gh->gh_owner == current) {
+			locked = 1;
+			break;
+		}
+	}
+	spin_unlock(&gl->gl_spin);
+
+	return locked;
+}
+
+static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl)
+{
+	return gl->gl_state == LM_ST_EXCLUSIVE;
+}
+
+static inline int gfs2_glock_is_held_dfrd(struct gfs2_glock *gl)
+{
+	return gl->gl_state == LM_ST_DEFERRED;
+}
+
+static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl)
+{
+	return gl->gl_state == LM_ST_SHARED;
+}
+
+static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
+{
+	int ret;
+	spin_lock(&gl->gl_spin);
+	ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3);
+	spin_unlock(&gl->gl_spin);
+	return ret;
+}
+
+int gfs2_glock_get(struct gfs2_sbd *sdp,
+		   u64 number, const struct gfs2_glock_operations *glops,
+		   int create, struct gfs2_glock **glp);
+void gfs2_glock_hold(struct gfs2_glock *gl);
+int gfs2_glock_put(struct gfs2_glock *gl);
+void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
+		      struct gfs2_holder *gh);
+void gfs2_holder_reinit(unsigned int state, unsigned flags,
+			struct gfs2_holder *gh);
+void gfs2_holder_uninit(struct gfs2_holder *gh);
+
+void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags);
+void gfs2_glock_drop_th(struct gfs2_glock *gl);
+
+int gfs2_glock_nq(struct gfs2_holder *gh);
+int gfs2_glock_poll(struct gfs2_holder *gh);
+int gfs2_glock_wait(struct gfs2_holder *gh);
+void gfs2_glock_dq(struct gfs2_holder *gh);
+
+int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time);
+
+void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
+int gfs2_glock_nq_num(struct gfs2_sbd *sdp,
+		      u64 number, const struct gfs2_glock_operations *glops,
+		      unsigned int state, int flags, struct gfs2_holder *gh);
+
+int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
+void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
+void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
+
+void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
+			     const struct gfs2_glock_operations *glops,
+			     unsigned int state, int flags);
+void gfs2_glock_inode_squish(struct inode *inode);
+
+/**
+ * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock
+ * @gl: the glock
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gh: the holder structure
+ *
+ * Returns: 0, GLR_*, or errno
+ */
+
+static inline int gfs2_glock_nq_init(struct gfs2_glock *gl,
+				     unsigned int state, int flags,
+				     struct gfs2_holder *gh)
+{
+	int error;
+
+	gfs2_holder_init(gl, state, flags, gh);
+
+	error = gfs2_glock_nq(gh);
+	if (error)
+		gfs2_holder_uninit(gh);
+
+	return error;
+}
+
+/*  Lock Value Block functions  */
+
+int gfs2_lvb_hold(struct gfs2_glock *gl);
+void gfs2_lvb_unhold(struct gfs2_glock *gl);
+
+void gfs2_glock_cb(void *cb_data, unsigned int type, void *data);
+
+void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl);
+void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
+
+void gfs2_scand_internal(struct gfs2_sbd *sdp);
+void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
+
+int __init gfs2_glock_init(void);
+
+#endif /* __GLOCK_DOT_H__ */
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
new file mode 100644
index 0000000..41a6b68
--- /dev/null
+++ b/fs/gfs2/glops.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "util.h"
+#include "trans.h"
+
+/**
+ * ail_empty_gl - remove all buffers for a given lock from the AIL
+ * @gl: the glock
+ *
+ * None of the buffers should be dirty, locked, or pinned.
+ */
+
+static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	unsigned int blocks;
+	struct list_head *head = &gl->gl_ail_list;
+	struct gfs2_bufdata *bd;
+	struct buffer_head *bh;
+	u64 blkno;
+	int error;
+
+	blocks = atomic_read(&gl->gl_ail_count);
+	if (!blocks)
+		return;
+
+	error = gfs2_trans_begin(sdp, 0, blocks);
+	if (gfs2_assert_withdraw(sdp, !error))
+		return;
+
+	gfs2_log_lock(sdp);
+	while (!list_empty(head)) {
+		bd = list_entry(head->next, struct gfs2_bufdata,
+				bd_ail_gl_list);
+		bh = bd->bd_bh;
+		blkno = bh->b_blocknr;
+		gfs2_assert_withdraw(sdp, !buffer_busy(bh));
+
+		bd->bd_ail = NULL;
+		list_del(&bd->bd_ail_st_list);
+		list_del(&bd->bd_ail_gl_list);
+		atomic_dec(&gl->gl_ail_count);
+		brelse(bh);
+		gfs2_log_unlock(sdp);
+
+		gfs2_trans_add_revoke(sdp, blkno);
+
+		gfs2_log_lock(sdp);
+	}
+	gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
+	gfs2_log_unlock(sdp);
+
+	gfs2_trans_end(sdp);
+	gfs2_log_flush(sdp, NULL);
+}
+
+/**
+ * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
+ * @gl: the glock
+ *
+ */
+
+static void gfs2_pte_inval(struct gfs2_glock *gl)
+{
+	struct gfs2_inode *ip;
+	struct inode *inode;
+
+	ip = gl->gl_object;
+	inode = &ip->i_inode;
+	if (!ip || !S_ISREG(ip->i_di.di_mode))
+		return;
+
+	if (!test_bit(GIF_PAGED, &ip->i_flags))
+		return;
+
+	unmap_shared_mapping_range(inode->i_mapping, 0, 0);
+
+	if (test_bit(GIF_SW_PAGED, &ip->i_flags))
+		set_bit(GLF_DIRTY, &gl->gl_flags);
+
+	clear_bit(GIF_SW_PAGED, &ip->i_flags);
+}
+
+/**
+ * gfs2_page_inval - Invalidate all pages associated with a glock
+ * @gl: the glock
+ *
+ */
+
+static void gfs2_page_inval(struct gfs2_glock *gl)
+{
+	struct gfs2_inode *ip;
+	struct inode *inode;
+
+	ip = gl->gl_object;
+	inode = &ip->i_inode;
+	if (!ip || !S_ISREG(ip->i_di.di_mode))
+		return;
+
+	truncate_inode_pages(inode->i_mapping, 0);
+	gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !inode->i_mapping->nrpages);
+	clear_bit(GIF_PAGED, &ip->i_flags);
+}
+
+/**
+ * gfs2_page_wait - Wait for writeback of data
+ * @gl: the glock
+ *
+ * Syncs data (not metadata) for a regular file.
+ * No-op for all other types.
+ */
+
+static void gfs2_page_wait(struct gfs2_glock *gl)
+{
+	struct gfs2_inode *ip = gl->gl_object;
+	struct inode *inode = &ip->i_inode;
+	struct address_space *mapping = inode->i_mapping;
+	int error;
+
+	if (!S_ISREG(ip->i_di.di_mode))
+		return;
+
+	error = filemap_fdatawait(mapping);
+
+	/* Put back any errors cleared by filemap_fdatawait()
+	   so they can be caught by someone who can pass them
+	   up to user space. */
+
+	if (error == -ENOSPC)
+		set_bit(AS_ENOSPC, &mapping->flags);
+	else if (error)
+		set_bit(AS_EIO, &mapping->flags);
+
+}
+
+static void gfs2_page_writeback(struct gfs2_glock *gl)
+{
+	struct gfs2_inode *ip = gl->gl_object;
+	struct inode *inode = &ip->i_inode;
+	struct address_space *mapping = inode->i_mapping;
+
+	if (!S_ISREG(ip->i_di.di_mode))
+		return;
+
+	filemap_fdatawrite(mapping);
+}
+
+/**
+ * meta_go_sync - sync out the metadata for this glock
+ * @gl: the glock
+ * @flags: DIO_*
+ *
+ * Called when demoting or unlocking an EX glock.  We must flush
+ * to disk all dirty buffers/pages relating to this glock, and must not
+ * not return to caller to demote/unlock the glock until I/O is complete.
+ */
+
+static void meta_go_sync(struct gfs2_glock *gl, int flags)
+{
+	if (!(flags & DIO_METADATA))
+		return;
+
+	if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
+		gfs2_log_flush(gl->gl_sbd, gl);
+		gfs2_meta_sync(gl);
+		if (flags & DIO_RELEASE)
+			gfs2_ail_empty_gl(gl);
+	}
+
+}
+
+/**
+ * meta_go_inval - invalidate the metadata for this glock
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void meta_go_inval(struct gfs2_glock *gl, int flags)
+{
+	if (!(flags & DIO_METADATA))
+		return;
+
+	gfs2_meta_inval(gl);
+	gl->gl_vn++;
+}
+
+/**
+ * inode_go_xmote_th - promote/demote a glock
+ * @gl: the glock
+ * @state: the requested state
+ * @flags:
+ *
+ */
+
+static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
+			      int flags)
+{
+	if (gl->gl_state != LM_ST_UNLOCKED)
+		gfs2_pte_inval(gl);
+	gfs2_glock_xmote_th(gl, state, flags);
+}
+
+/**
+ * inode_go_xmote_bh - After promoting/demoting a glock
+ * @gl: the glock
+ *
+ */
+
+static void inode_go_xmote_bh(struct gfs2_glock *gl)
+{
+	struct gfs2_holder *gh = gl->gl_req_gh;
+	struct buffer_head *bh;
+	int error;
+
+	if (gl->gl_state != LM_ST_UNLOCKED &&
+	    (!gh || !(gh->gh_flags & GL_SKIP))) {
+		error = gfs2_meta_read(gl, gl->gl_name.ln_number, 0, &bh);
+		if (!error)
+			brelse(bh);
+	}
+}
+
+/**
+ * inode_go_drop_th - unlock a glock
+ * @gl: the glock
+ *
+ * Invoked from rq_demote().
+ * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long)
+ * is being purged from our node's glock cache; we're dropping lock.
+ */
+
+static void inode_go_drop_th(struct gfs2_glock *gl)
+{
+	gfs2_pte_inval(gl);
+	gfs2_glock_drop_th(gl);
+}
+
+/**
+ * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
+ * @gl: the glock protecting the inode
+ * @flags:
+ *
+ */
+
+static void inode_go_sync(struct gfs2_glock *gl, int flags)
+{
+	int meta = (flags & DIO_METADATA);
+	int data = (flags & DIO_DATA);
+
+	if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
+		if (meta && data) {
+			gfs2_page_writeback(gl);
+			gfs2_log_flush(gl->gl_sbd, gl);
+			gfs2_meta_sync(gl);
+			gfs2_page_wait(gl);
+			clear_bit(GLF_DIRTY, &gl->gl_flags);
+		} else if (meta) {
+			gfs2_log_flush(gl->gl_sbd, gl);
+			gfs2_meta_sync(gl);
+		} else if (data) {
+			gfs2_page_writeback(gl);
+			gfs2_page_wait(gl);
+		}
+		if (flags & DIO_RELEASE)
+			gfs2_ail_empty_gl(gl);
+	}
+}
+
+/**
+ * inode_go_inval - prepare a inode glock to be released
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void inode_go_inval(struct gfs2_glock *gl, int flags)
+{
+	int meta = (flags & DIO_METADATA);
+	int data = (flags & DIO_DATA);
+
+	if (meta) {
+		gfs2_meta_inval(gl);
+		gl->gl_vn++;
+	}
+	if (data)
+		gfs2_page_inval(gl);
+}
+
+/**
+ * inode_go_demote_ok - Check to see if it's ok to unlock an inode glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int inode_go_demote_ok(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	int demote = 0;
+
+	if (!gl->gl_object && !gl->gl_aspace->i_mapping->nrpages)
+		demote = 1;
+	else if (!sdp->sd_args.ar_localcaching &&
+		 time_after_eq(jiffies, gl->gl_stamp +
+			       gfs2_tune_get(sdp, gt_demote_secs) * HZ))
+		demote = 1;
+
+	return demote;
+}
+
+/**
+ * inode_go_lock - operation done after an inode lock is locked by a process
+ * @gl: the glock
+ * @flags:
+ *
+ * Returns: errno
+ */
+
+static int inode_go_lock(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	struct gfs2_inode *ip = gl->gl_object;
+	int error = 0;
+
+	if (!ip)
+		return 0;
+
+	if (ip->i_vn != gl->gl_vn) {
+		error = gfs2_inode_refresh(ip);
+		if (error)
+			return error;
+		gfs2_inode_attr_in(ip);
+	}
+
+	if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) &&
+	    (gl->gl_state == LM_ST_EXCLUSIVE) &&
+	    (gh->gh_flags & GL_LOCAL_EXCL))
+		error = gfs2_truncatei_resume(ip);
+
+	return error;
+}
+
+/**
+ * inode_go_unlock - operation done before an inode lock is unlocked by a
+ *		     process
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void inode_go_unlock(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	struct gfs2_inode *ip = gl->gl_object;
+
+	if (ip == NULL)
+		return;
+	if (test_bit(GLF_DIRTY, &gl->gl_flags))
+		gfs2_inode_attr_in(ip);
+	gfs2_meta_cache_flush(ip);
+}
+
+/**
+ * inode_greedy -
+ * @gl: the glock
+ *
+ */
+
+static void inode_greedy(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	struct gfs2_inode *ip = gl->gl_object;
+	unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum);
+	unsigned int max = gfs2_tune_get(sdp, gt_greedy_max);
+	unsigned int new_time;
+
+	spin_lock(&ip->i_spin);
+
+	if (time_after(ip->i_last_pfault + quantum, jiffies)) {
+		new_time = ip->i_greedy + quantum;
+		if (new_time > max)
+			new_time = max;
+	} else {
+		new_time = ip->i_greedy - quantum;
+		if (!new_time || new_time > max)
+			new_time = 1;
+	}
+
+	ip->i_greedy = new_time;
+
+	spin_unlock(&ip->i_spin);
+
+	iput(&ip->i_inode);
+}
+
+/**
+ * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int rgrp_go_demote_ok(struct gfs2_glock *gl)
+{
+	return !gl->gl_aspace->i_mapping->nrpages;
+}
+
+/**
+ * rgrp_go_lock - operation done after an rgrp lock is locked by
+ *    a first holder on this node.
+ * @gl: the glock
+ * @flags:
+ *
+ * Returns: errno
+ */
+
+static int rgrp_go_lock(struct gfs2_holder *gh)
+{
+	return gfs2_rgrp_bh_get(gh->gh_gl->gl_object);
+}
+
+/**
+ * rgrp_go_unlock - operation done before an rgrp lock is unlocked by
+ *    a last holder on this node.
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void rgrp_go_unlock(struct gfs2_holder *gh)
+{
+	gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
+}
+
+/**
+ * trans_go_xmote_th - promote/demote the transaction glock
+ * @gl: the glock
+ * @state: the requested state
+ * @flags:
+ *
+ */
+
+static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
+			      int flags)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+
+	if (gl->gl_state != LM_ST_UNLOCKED &&
+	    test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+		gfs2_meta_syncfs(sdp);
+		gfs2_log_shutdown(sdp);
+	}
+
+	gfs2_glock_xmote_th(gl, state, flags);
+}
+
+/**
+ * trans_go_xmote_bh - After promoting/demoting the transaction glock
+ * @gl: the glock
+ *
+ */
+
+static void trans_go_xmote_bh(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
+	struct gfs2_glock *j_gl = ip->i_gl;
+	struct gfs2_log_header head;
+	int error;
+
+	if (gl->gl_state != LM_ST_UNLOCKED &&
+	    test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+		gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode));
+		j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
+
+		error = gfs2_find_jhead(sdp->sd_jdesc, &head);
+		if (error)
+			gfs2_consist(sdp);
+		if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT))
+			gfs2_consist(sdp);
+
+		/*  Initialize some head of the log stuff  */
+		if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
+			sdp->sd_log_sequence = head.lh_sequence + 1;
+			gfs2_log_pointers_init(sdp, head.lh_blkno);
+		}
+	}
+}
+
+/**
+ * trans_go_drop_th - unlock the transaction glock
+ * @gl: the glock
+ *
+ * We want to sync the device even with localcaching.  Remember
+ * that localcaching journal replay only marks buffers dirty.
+ */
+
+static void trans_go_drop_th(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+
+	if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+		gfs2_meta_syncfs(sdp);
+		gfs2_log_shutdown(sdp);
+	}
+
+	gfs2_glock_drop_th(gl);
+}
+
+/**
+ * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int quota_go_demote_ok(struct gfs2_glock *gl)
+{
+	return !atomic_read(&gl->gl_lvb_count);
+}
+
+const struct gfs2_glock_operations gfs2_meta_glops = {
+	.go_xmote_th = gfs2_glock_xmote_th,
+	.go_drop_th = gfs2_glock_drop_th,
+	.go_type = LM_TYPE_META,
+};
+
+const struct gfs2_glock_operations gfs2_inode_glops = {
+	.go_xmote_th = inode_go_xmote_th,
+	.go_xmote_bh = inode_go_xmote_bh,
+	.go_drop_th = inode_go_drop_th,
+	.go_sync = inode_go_sync,
+	.go_inval = inode_go_inval,
+	.go_demote_ok = inode_go_demote_ok,
+	.go_lock = inode_go_lock,
+	.go_unlock = inode_go_unlock,
+	.go_greedy = inode_greedy,
+	.go_type = LM_TYPE_INODE,
+};
+
+const struct gfs2_glock_operations gfs2_rgrp_glops = {
+	.go_xmote_th = gfs2_glock_xmote_th,
+	.go_drop_th = gfs2_glock_drop_th,
+	.go_sync = meta_go_sync,
+	.go_inval = meta_go_inval,
+	.go_demote_ok = rgrp_go_demote_ok,
+	.go_lock = rgrp_go_lock,
+	.go_unlock = rgrp_go_unlock,
+	.go_type = LM_TYPE_RGRP,
+};
+
+const struct gfs2_glock_operations gfs2_trans_glops = {
+	.go_xmote_th = trans_go_xmote_th,
+	.go_xmote_bh = trans_go_xmote_bh,
+	.go_drop_th = trans_go_drop_th,
+	.go_type = LM_TYPE_NONDISK,
+};
+
+const struct gfs2_glock_operations gfs2_iopen_glops = {
+	.go_xmote_th = gfs2_glock_xmote_th,
+	.go_drop_th = gfs2_glock_drop_th,
+	.go_type = LM_TYPE_IOPEN,
+};
+
+const struct gfs2_glock_operations gfs2_flock_glops = {
+	.go_xmote_th = gfs2_glock_xmote_th,
+	.go_drop_th = gfs2_glock_drop_th,
+	.go_type = LM_TYPE_FLOCK,
+};
+
+const struct gfs2_glock_operations gfs2_nondisk_glops = {
+	.go_xmote_th = gfs2_glock_xmote_th,
+	.go_drop_th = gfs2_glock_drop_th,
+	.go_type = LM_TYPE_NONDISK,
+};
+
+const struct gfs2_glock_operations gfs2_quota_glops = {
+	.go_xmote_th = gfs2_glock_xmote_th,
+	.go_drop_th = gfs2_glock_drop_th,
+	.go_demote_ok = quota_go_demote_ok,
+	.go_type = LM_TYPE_QUOTA,
+};
+
+const struct gfs2_glock_operations gfs2_journal_glops = {
+	.go_xmote_th = gfs2_glock_xmote_th,
+	.go_drop_th = gfs2_glock_drop_th,
+	.go_type = LM_TYPE_JOURNAL,
+};
+
diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h
new file mode 100644
index 0000000..a1d9b5b
--- /dev/null
+++ b/fs/gfs2/glops.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __GLOPS_DOT_H__
+#define __GLOPS_DOT_H__
+
+#include "incore.h"
+
+extern const struct gfs2_glock_operations gfs2_meta_glops;
+extern const struct gfs2_glock_operations gfs2_inode_glops;
+extern const struct gfs2_glock_operations gfs2_rgrp_glops;
+extern const struct gfs2_glock_operations gfs2_trans_glops;
+extern const struct gfs2_glock_operations gfs2_iopen_glops;
+extern const struct gfs2_glock_operations gfs2_flock_glops;
+extern const struct gfs2_glock_operations gfs2_nondisk_glops;
+extern const struct gfs2_glock_operations gfs2_quota_glops;
+extern const struct gfs2_glock_operations gfs2_journal_glops;
+
+#endif /* __GLOPS_DOT_H__ */
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
new file mode 100644
index 0000000..118dc69
--- /dev/null
+++ b/fs/gfs2/incore.h
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __INCORE_DOT_H__
+#define __INCORE_DOT_H__
+
+#include <linux/fs.h>
+
+#define DIO_WAIT	0x00000010
+#define DIO_METADATA	0x00000020
+#define DIO_DATA	0x00000040
+#define DIO_RELEASE	0x00000080
+#define DIO_ALL		0x00000100
+
+struct gfs2_log_operations;
+struct gfs2_log_element;
+struct gfs2_holder;
+struct gfs2_glock;
+struct gfs2_quota_data;
+struct gfs2_trans;
+struct gfs2_ail;
+struct gfs2_jdesc;
+struct gfs2_sbd;
+
+typedef void (*gfs2_glop_bh_t) (struct gfs2_glock *gl, unsigned int ret);
+
+/*
+ * Structure of operations that are associated with each
+ * type of element in the log.
+ */
+
+struct gfs2_log_operations {
+	void (*lo_add) (struct gfs2_sbd *sdp, struct gfs2_log_element *le);
+	void (*lo_incore_commit) (struct gfs2_sbd *sdp, struct gfs2_trans *tr);
+	void (*lo_before_commit) (struct gfs2_sbd *sdp);
+	void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai);
+	void (*lo_before_scan) (struct gfs2_jdesc *jd,
+				struct gfs2_log_header *head, int pass);
+	int (*lo_scan_elements) (struct gfs2_jdesc *jd, unsigned int start,
+				 struct gfs2_log_descriptor *ld, __be64 *ptr,
+				 int pass);
+	void (*lo_after_scan) (struct gfs2_jdesc *jd, int error, int pass);
+	const char *lo_name;
+};
+
+struct gfs2_log_element {
+	struct list_head le_list;
+	const struct gfs2_log_operations *le_ops;
+};
+
+struct gfs2_bitmap {
+	struct buffer_head *bi_bh;
+	char *bi_clone;
+	u32 bi_offset;
+	u32 bi_start;
+	u32 bi_len;
+};
+
+struct gfs2_rgrpd {
+	struct list_head rd_list;	/* Link with superblock */
+	struct list_head rd_list_mru;
+	struct list_head rd_recent;	/* Recently used rgrps */
+	struct gfs2_glock *rd_gl;	/* Glock for this rgrp */
+	struct gfs2_rindex rd_ri;
+	struct gfs2_rgrp rd_rg;
+	u64 rd_rg_vn;
+	struct gfs2_bitmap *rd_bits;
+	unsigned int rd_bh_count;
+	struct mutex rd_mutex;
+	u32 rd_free_clone;
+	struct gfs2_log_element rd_le;
+	u32 rd_last_alloc_data;
+	u32 rd_last_alloc_meta;
+	struct gfs2_sbd *rd_sbd;
+};
+
+enum gfs2_state_bits {
+	BH_Pinned = BH_PrivateStart,
+	BH_Escaped = BH_PrivateStart + 1,
+};
+
+BUFFER_FNS(Pinned, pinned)
+TAS_BUFFER_FNS(Pinned, pinned)
+BUFFER_FNS(Escaped, escaped)
+TAS_BUFFER_FNS(Escaped, escaped)
+
+struct gfs2_bufdata {
+	struct buffer_head *bd_bh;
+	struct gfs2_glock *bd_gl;
+
+	struct list_head bd_list_tr;
+	struct gfs2_log_element bd_le;
+
+	struct gfs2_ail *bd_ail;
+	struct list_head bd_ail_st_list;
+	struct list_head bd_ail_gl_list;
+};
+
+struct gfs2_glock_operations {
+	void (*go_xmote_th) (struct gfs2_glock * gl, unsigned int state,
+			     int flags);
+	void (*go_xmote_bh) (struct gfs2_glock * gl);
+	void (*go_drop_th) (struct gfs2_glock * gl);
+	void (*go_drop_bh) (struct gfs2_glock * gl);
+	void (*go_sync) (struct gfs2_glock * gl, int flags);
+	void (*go_inval) (struct gfs2_glock * gl, int flags);
+	int (*go_demote_ok) (struct gfs2_glock * gl);
+	int (*go_lock) (struct gfs2_holder * gh);
+	void (*go_unlock) (struct gfs2_holder * gh);
+	void (*go_callback) (struct gfs2_glock * gl, unsigned int state);
+	void (*go_greedy) (struct gfs2_glock * gl);
+	const int go_type;
+};
+
+enum {
+	/* Actions */
+	HIF_MUTEX		= 0,
+	HIF_PROMOTE		= 1,
+	HIF_DEMOTE		= 2,
+	HIF_GREEDY		= 3,
+
+	/* States */
+	HIF_ALLOCED		= 4,
+	HIF_DEALLOC		= 5,
+	HIF_HOLDER		= 6,
+	HIF_FIRST		= 7,
+	HIF_ABORTED		= 9,
+};
+
+struct gfs2_holder {
+	struct list_head gh_list;
+
+	struct gfs2_glock *gh_gl;
+	struct task_struct *gh_owner;
+	unsigned int gh_state;
+	unsigned gh_flags;
+
+	int gh_error;
+	unsigned long gh_iflags;
+	struct completion gh_wait;
+	unsigned long gh_ip;
+};
+
+enum {
+	GLF_LOCK		= 1,
+	GLF_STICKY		= 2,
+	GLF_PREFETCH		= 3,
+	GLF_DIRTY		= 5,
+	GLF_SKIP_WAITERS2	= 6,
+	GLF_GREEDY		= 7,
+};
+
+struct gfs2_glock {
+	struct hlist_node gl_list;
+	unsigned long gl_flags;		/* GLF_... */
+	struct lm_lockname gl_name;
+	atomic_t gl_ref;
+
+	spinlock_t gl_spin;
+
+	unsigned int gl_state;
+	unsigned int gl_hash;
+	struct task_struct *gl_owner;
+	unsigned long gl_ip;
+	struct list_head gl_holders;
+	struct list_head gl_waiters1;	/* HIF_MUTEX */
+	struct list_head gl_waiters2;	/* HIF_DEMOTE, HIF_GREEDY */
+	struct list_head gl_waiters3;	/* HIF_PROMOTE */
+
+	const struct gfs2_glock_operations *gl_ops;
+
+	struct gfs2_holder *gl_req_gh;
+	gfs2_glop_bh_t gl_req_bh;
+
+	void *gl_lock;
+	char *gl_lvb;
+	atomic_t gl_lvb_count;
+
+	u64 gl_vn;
+	unsigned long gl_stamp;
+	void *gl_object;
+
+	struct list_head gl_reclaim;
+
+	struct gfs2_sbd *gl_sbd;
+
+	struct inode *gl_aspace;
+	struct gfs2_log_element gl_le;
+	struct list_head gl_ail_list;
+	atomic_t gl_ail_count;
+};
+
+struct gfs2_alloc {
+	/* Quota stuff */
+
+	struct gfs2_quota_data *al_qd[2*MAXQUOTAS];
+	struct gfs2_holder al_qd_ghs[2*MAXQUOTAS];
+	unsigned int al_qd_num;
+
+	u32 al_requested; /* Filled in by caller of gfs2_inplace_reserve() */
+	u32 al_alloced; /* Filled in by gfs2_alloc_*() */
+
+	/* Filled in by gfs2_inplace_reserve() */
+
+	unsigned int al_line;
+	char *al_file;
+	struct gfs2_holder al_ri_gh;
+	struct gfs2_holder al_rgd_gh;
+	struct gfs2_rgrpd *al_rgd;
+
+};
+
+enum {
+	GIF_QD_LOCKED		= 1,
+	GIF_PAGED		= 2,
+	GIF_SW_PAGED		= 3,
+};
+
+struct gfs2_inode {
+	struct inode i_inode;
+	struct gfs2_inum i_num;
+
+	unsigned long i_flags;		/* GIF_... */
+
+	u64 i_vn;
+	struct gfs2_dinode i_di; /* To be replaced by ref to block */
+
+	struct gfs2_glock *i_gl; /* Move into i_gh? */
+	struct gfs2_holder i_iopen_gh;
+	struct gfs2_holder i_gh; /* for prepare/commit_write only */
+	struct gfs2_alloc i_alloc;
+	u64 i_last_rg_alloc;
+
+	spinlock_t i_spin;
+	struct rw_semaphore i_rw_mutex;
+	unsigned int i_greedy;
+	unsigned long i_last_pfault;
+
+	struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
+};
+
+/*
+ * Since i_inode is the first element of struct gfs2_inode,
+ * this is effectively a cast.
+ */
+static inline struct gfs2_inode *GFS2_I(struct inode *inode)
+{
+	return container_of(inode, struct gfs2_inode, i_inode);
+}
+
+/* To be removed? */
+static inline struct gfs2_sbd *GFS2_SB(struct inode *inode)
+{
+	return inode->i_sb->s_fs_info;
+}
+
+enum {
+	GFF_DID_DIRECT_ALLOC	= 0,
+	GFF_EXLOCK = 1,
+};
+
+struct gfs2_file {
+	unsigned long f_flags;		/* GFF_... */
+	struct mutex f_fl_mutex;
+	struct gfs2_holder f_fl_gh;
+};
+
+struct gfs2_revoke {
+	struct gfs2_log_element rv_le;
+	u64 rv_blkno;
+};
+
+struct gfs2_revoke_replay {
+	struct list_head rr_list;
+	u64 rr_blkno;
+	unsigned int rr_where;
+};
+
+enum {
+	QDF_USER		= 0,
+	QDF_CHANGE		= 1,
+	QDF_LOCKED		= 2,
+};
+
+struct gfs2_quota_lvb {
+        __be32 qb_magic;
+        u32 __pad;
+        __be64 qb_limit;      /* Hard limit of # blocks to alloc */
+        __be64 qb_warn;       /* Warn user when alloc is above this # */
+        __be64 qb_value;       /* Current # blocks allocated */
+};
+
+struct gfs2_quota_data {
+	struct list_head qd_list;
+	unsigned int qd_count;
+
+	u32 qd_id;
+	unsigned long qd_flags;		/* QDF_... */
+
+	s64 qd_change;
+	s64 qd_change_sync;
+
+	unsigned int qd_slot;
+	unsigned int qd_slot_count;
+
+	struct buffer_head *qd_bh;
+	struct gfs2_quota_change *qd_bh_qc;
+	unsigned int qd_bh_count;
+
+	struct gfs2_glock *qd_gl;
+	struct gfs2_quota_lvb qd_qb;
+
+	u64 qd_sync_gen;
+	unsigned long qd_last_warn;
+	unsigned long qd_last_touched;
+};
+
+struct gfs2_log_buf {
+	struct list_head lb_list;
+	struct buffer_head *lb_bh;
+	struct buffer_head *lb_real;
+};
+
+struct gfs2_trans {
+	unsigned long tr_ip;
+
+	unsigned int tr_blocks;
+	unsigned int tr_revokes;
+	unsigned int tr_reserved;
+
+	struct gfs2_holder tr_t_gh;
+
+	int tr_touched;
+
+	unsigned int tr_num_buf;
+	unsigned int tr_num_buf_new;
+	unsigned int tr_num_buf_rm;
+	struct list_head tr_list_buf;
+
+	unsigned int tr_num_revoke;
+	unsigned int tr_num_revoke_rm;
+};
+
+struct gfs2_ail {
+	struct list_head ai_list;
+
+	unsigned int ai_first;
+	struct list_head ai_ail1_list;
+	struct list_head ai_ail2_list;
+
+	u64 ai_sync_gen;
+};
+
+struct gfs2_jdesc {
+	struct list_head jd_list;
+
+	struct inode *jd_inode;
+	unsigned int jd_jid;
+	int jd_dirty;
+
+	unsigned int jd_blocks;
+};
+
+#define GFS2_GLOCKD_DEFAULT	1
+#define GFS2_GLOCKD_MAX		16
+
+#define GFS2_QUOTA_DEFAULT	GFS2_QUOTA_OFF
+#define GFS2_QUOTA_OFF		0
+#define GFS2_QUOTA_ACCOUNT	1
+#define GFS2_QUOTA_ON		2
+
+#define GFS2_DATA_DEFAULT	GFS2_DATA_ORDERED
+#define GFS2_DATA_WRITEBACK	1
+#define GFS2_DATA_ORDERED	2
+
+struct gfs2_args {
+	char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */
+	char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */
+	char ar_hostdata[GFS2_LOCKNAME_LEN]; /* Host specific data */
+	int ar_spectator; /* Don't get a journal because we're always RO */
+	int ar_ignore_local_fs; /* Don't optimize even if local_fs is 1 */
+	int ar_localflocks; /* Let the VFS do flock|fcntl locks for us */
+	int ar_localcaching; /* Local-style caching (dangerous on multihost) */
+	int ar_debug; /* Oops on errors instead of trying to be graceful */
+	int ar_upgrade; /* Upgrade ondisk/multihost format */
+	unsigned int ar_num_glockd; /* Number of glockd threads */
+	int ar_posix_acl; /* Enable posix acls */
+	int ar_quota; /* off/account/on */
+	int ar_suiddir; /* suiddir support */
+	int ar_data; /* ordered/writeback */
+};
+
+struct gfs2_tune {
+	spinlock_t gt_spin;
+
+	unsigned int gt_ilimit;
+	unsigned int gt_ilimit_tries;
+	unsigned int gt_ilimit_min;
+	unsigned int gt_demote_secs; /* Cache retention for unheld glock */
+	unsigned int gt_incore_log_blocks;
+	unsigned int gt_log_flush_secs;
+	unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
+
+	unsigned int gt_scand_secs;
+	unsigned int gt_recoverd_secs;
+	unsigned int gt_logd_secs;
+	unsigned int gt_quotad_secs;
+
+	unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */
+	unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */
+	unsigned int gt_quota_scale_num; /* Numerator */
+	unsigned int gt_quota_scale_den; /* Denominator */
+	unsigned int gt_quota_cache_secs;
+	unsigned int gt_quota_quantum; /* Secs between syncs to quota file */
+	unsigned int gt_atime_quantum; /* Min secs between atime updates */
+	unsigned int gt_new_files_jdata;
+	unsigned int gt_new_files_directio;
+	unsigned int gt_max_atomic_write; /* Split big writes into this size */
+	unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
+	unsigned int gt_lockdump_size;
+	unsigned int gt_stall_secs; /* Detects trouble! */
+	unsigned int gt_complain_secs;
+	unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
+	unsigned int gt_entries_per_readdir;
+	unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */
+	unsigned int gt_greedy_default;
+	unsigned int gt_greedy_quantum;
+	unsigned int gt_greedy_max;
+	unsigned int gt_statfs_quantum;
+	unsigned int gt_statfs_slow;
+};
+
+enum {
+	SDF_JOURNAL_CHECKED	= 0,
+	SDF_JOURNAL_LIVE	= 1,
+	SDF_SHUTDOWN		= 2,
+	SDF_NOATIME		= 3,
+};
+
+#define GFS2_FSNAME_LEN		256
+
+struct gfs2_sbd {
+	struct super_block *sd_vfs;
+	struct super_block *sd_vfs_meta;
+	struct kobject sd_kobj;
+	unsigned long sd_flags;	/* SDF_... */
+	struct gfs2_sb sd_sb;
+
+	/* Constants computed on mount */
+
+	u32 sd_fsb2bb;
+	u32 sd_fsb2bb_shift;
+	u32 sd_diptrs;	/* Number of pointers in a dinode */
+	u32 sd_inptrs;	/* Number of pointers in a indirect block */
+	u32 sd_jbsize;	/* Size of a journaled data block */
+	u32 sd_hash_bsize;	/* sizeof(exhash block) */
+	u32 sd_hash_bsize_shift;
+	u32 sd_hash_ptrs;	/* Number of pointers in a hash block */
+	u32 sd_qc_per_block;
+	u32 sd_max_dirres;	/* Max blocks needed to add a directory entry */
+	u32 sd_max_height;	/* Max height of a file's metadata tree */
+	u64 sd_heightsize[GFS2_MAX_META_HEIGHT];
+	u32 sd_max_jheight; /* Max height of journaled file's meta tree */
+	u64 sd_jheightsize[GFS2_MAX_META_HEIGHT];
+
+	struct gfs2_args sd_args;	/* Mount arguments */
+	struct gfs2_tune sd_tune;	/* Filesystem tuning structure */
+
+	/* Lock Stuff */
+
+	struct lm_lockstruct sd_lockstruct;
+	struct list_head sd_reclaim_list;
+	spinlock_t sd_reclaim_lock;
+	wait_queue_head_t sd_reclaim_wq;
+	atomic_t sd_reclaim_count;
+	struct gfs2_holder sd_live_gh;
+	struct gfs2_glock *sd_rename_gl;
+	struct gfs2_glock *sd_trans_gl;
+
+	/* Inode Stuff */
+
+	struct inode *sd_master_dir;
+	struct inode *sd_jindex;
+	struct inode *sd_inum_inode;
+	struct inode *sd_statfs_inode;
+	struct inode *sd_ir_inode;
+	struct inode *sd_sc_inode;
+	struct inode *sd_qc_inode;
+	struct inode *sd_rindex;
+	struct inode *sd_quota_inode;
+
+	/* Inum stuff */
+
+	struct mutex sd_inum_mutex;
+
+	/* StatFS stuff */
+
+	spinlock_t sd_statfs_spin;
+	struct mutex sd_statfs_mutex;
+	struct gfs2_statfs_change sd_statfs_master;
+	struct gfs2_statfs_change sd_statfs_local;
+	unsigned long sd_statfs_sync_time;
+
+	/* Resource group stuff */
+
+	u64 sd_rindex_vn;
+	spinlock_t sd_rindex_spin;
+	struct mutex sd_rindex_mutex;
+	struct list_head sd_rindex_list;
+	struct list_head sd_rindex_mru_list;
+	struct list_head sd_rindex_recent_list;
+	struct gfs2_rgrpd *sd_rindex_forward;
+	unsigned int sd_rgrps;
+
+	/* Journal index stuff */
+
+	struct list_head sd_jindex_list;
+	spinlock_t sd_jindex_spin;
+	struct mutex sd_jindex_mutex;
+	unsigned int sd_journals;
+	unsigned long sd_jindex_refresh_time;
+
+	struct gfs2_jdesc *sd_jdesc;
+	struct gfs2_holder sd_journal_gh;
+	struct gfs2_holder sd_jinode_gh;
+
+	struct gfs2_holder sd_ir_gh;
+	struct gfs2_holder sd_sc_gh;
+	struct gfs2_holder sd_qc_gh;
+
+	/* Daemon stuff */
+
+	struct task_struct *sd_scand_process;
+	struct task_struct *sd_recoverd_process;
+	struct task_struct *sd_logd_process;
+	struct task_struct *sd_quotad_process;
+	struct task_struct *sd_glockd_process[GFS2_GLOCKD_MAX];
+	unsigned int sd_glockd_num;
+
+	/* Quota stuff */
+
+	struct list_head sd_quota_list;
+	atomic_t sd_quota_count;
+	spinlock_t sd_quota_spin;
+	struct mutex sd_quota_mutex;
+
+	unsigned int sd_quota_slots;
+	unsigned int sd_quota_chunks;
+	unsigned char **sd_quota_bitmap;
+
+	u64 sd_quota_sync_gen;
+	unsigned long sd_quota_sync_time;
+
+	/* Log stuff */
+
+	spinlock_t sd_log_lock;
+
+	unsigned int sd_log_blks_reserved;
+	unsigned int sd_log_commited_buf;
+	unsigned int sd_log_commited_revoke;
+
+	unsigned int sd_log_num_gl;
+	unsigned int sd_log_num_buf;
+	unsigned int sd_log_num_revoke;
+	unsigned int sd_log_num_rg;
+	unsigned int sd_log_num_databuf;
+	unsigned int sd_log_num_jdata;
+	unsigned int sd_log_num_hdrs;
+
+	struct list_head sd_log_le_gl;
+	struct list_head sd_log_le_buf;
+	struct list_head sd_log_le_revoke;
+	struct list_head sd_log_le_rg;
+	struct list_head sd_log_le_databuf;
+
+	unsigned int sd_log_blks_free;
+	struct mutex sd_log_reserve_mutex;
+
+	u64 sd_log_sequence;
+	unsigned int sd_log_head;
+	unsigned int sd_log_tail;
+	int sd_log_idle;
+
+	unsigned long sd_log_flush_time;
+	struct rw_semaphore sd_log_flush_lock;
+	struct list_head sd_log_flush_list;
+
+	unsigned int sd_log_flush_head;
+	u64 sd_log_flush_wrapped;
+
+	struct list_head sd_ail1_list;
+	struct list_head sd_ail2_list;
+	u64 sd_ail_sync_gen;
+
+	/* Replay stuff */
+
+	struct list_head sd_revoke_list;
+	unsigned int sd_replay_tail;
+
+	unsigned int sd_found_blocks;
+	unsigned int sd_found_revokes;
+	unsigned int sd_replayed_blocks;
+
+	/* For quiescing the filesystem */
+
+	struct gfs2_holder sd_freeze_gh;
+	struct mutex sd_freeze_lock;
+	unsigned int sd_freeze_count;
+
+	/* Counters */
+
+	atomic_t sd_glock_count;
+	atomic_t sd_glock_held_count;
+	atomic_t sd_inode_count;
+	atomic_t sd_reclaimed;
+
+	char sd_fsname[GFS2_FSNAME_LEN];
+	char sd_table_name[GFS2_FSNAME_LEN];
+	char sd_proto_name[GFS2_FSNAME_LEN];
+
+	/* Debugging crud */
+
+	unsigned long sd_last_warning;
+	struct vfsmount *sd_gfs2mnt;
+};
+
+#endif /* __INCORE_DOT_H__ */
+
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
new file mode 100644
index 0000000..57c43ac
--- /dev/null
+++ b/fs/gfs2/inode.c
@@ -0,0 +1,1379 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/posix_acl.h>
+#include <linux/sort.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+#include <linux/security.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "bmap.h"
+#include "dir.h"
+#include "eattr.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "ops_address.h"
+#include "ops_file.h"
+#include "ops_inode.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+/**
+ * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode
+ * @ip: The GFS2 inode (with embedded disk inode data)
+ * @inode:  The Linux VFS inode
+ *
+ */
+
+void gfs2_inode_attr_in(struct gfs2_inode *ip)
+{
+	struct inode *inode = &ip->i_inode;
+	struct gfs2_dinode *di = &ip->i_di;
+
+	inode->i_ino = ip->i_num.no_addr;
+
+	switch (di->di_mode & S_IFMT) {
+	case S_IFBLK:
+	case S_IFCHR:
+		inode->i_rdev = MKDEV(di->di_major, di->di_minor);
+		break;
+	default:
+		inode->i_rdev = 0;
+		break;
+	};
+
+	inode->i_mode = di->di_mode;
+	inode->i_nlink = di->di_nlink;
+	inode->i_uid = di->di_uid;
+	inode->i_gid = di->di_gid;
+	i_size_write(inode, di->di_size);
+	inode->i_atime.tv_sec = di->di_atime;
+	inode->i_mtime.tv_sec = di->di_mtime;
+	inode->i_ctime.tv_sec = di->di_ctime;
+	inode->i_atime.tv_nsec = 0;
+	inode->i_mtime.tv_nsec = 0;
+	inode->i_ctime.tv_nsec = 0;
+	inode->i_blocks = di->di_blocks <<
+		(GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT);
+
+	if (di->di_flags & GFS2_DIF_IMMUTABLE)
+		inode->i_flags |= S_IMMUTABLE;
+	else
+		inode->i_flags &= ~S_IMMUTABLE;
+
+	if (di->di_flags & GFS2_DIF_APPENDONLY)
+		inode->i_flags |= S_APPEND;
+	else
+		inode->i_flags &= ~S_APPEND;
+}
+
+/**
+ * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode
+ * @ip: The GFS2 inode
+ *
+ * Only copy out the attributes that we want the VFS layer
+ * to be able to modify.
+ */
+
+void gfs2_inode_attr_out(struct gfs2_inode *ip)
+{
+	struct inode *inode = &ip->i_inode;
+	struct gfs2_dinode *di = &ip->i_di;
+	gfs2_assert_withdraw(GFS2_SB(inode),
+		(di->di_mode & S_IFMT) == (inode->i_mode & S_IFMT));
+	di->di_mode = inode->i_mode;
+	di->di_uid = inode->i_uid;
+	di->di_gid = inode->i_gid;
+	di->di_atime = inode->i_atime.tv_sec;
+	di->di_mtime = inode->i_mtime.tv_sec;
+	di->di_ctime = inode->i_ctime.tv_sec;
+}
+
+static int iget_test(struct inode *inode, void *opaque)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_inum *inum = opaque;
+
+	if (ip && ip->i_num.no_addr == inum->no_addr)
+		return 1;
+
+	return 0;
+}
+
+static int iget_set(struct inode *inode, void *opaque)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_inum *inum = opaque;
+
+	ip->i_num = *inum;
+	return 0;
+}
+
+struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum)
+{
+	return ilookup5(sb, (unsigned long)inum->no_formal_ino,
+			iget_test, inum);
+}
+
+static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum)
+{
+	return iget5_locked(sb, (unsigned long)inum->no_formal_ino,
+		     iget_test, iget_set, inum);
+}
+
+/**
+ * gfs2_inode_lookup - Lookup an inode
+ * @sb: The super block
+ * @inum: The inode number
+ * @type: The type of the inode
+ *
+ * Returns: A VFS inode, or an error
+ */
+
+struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned int type)
+{
+	struct inode *inode = gfs2_iget(sb, inum);
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_glock *io_gl;
+	int error;
+
+	if (inode->i_state & I_NEW) {
+		struct gfs2_sbd *sdp = GFS2_SB(inode);
+		umode_t mode = DT2IF(type);
+		inode->i_private = ip;
+		inode->i_mode = mode;
+
+		if (S_ISREG(mode)) {
+			inode->i_op = &gfs2_file_iops;
+			inode->i_fop = &gfs2_file_fops;
+			inode->i_mapping->a_ops = &gfs2_file_aops;
+		} else if (S_ISDIR(mode)) {
+			inode->i_op = &gfs2_dir_iops;
+			inode->i_fop = &gfs2_dir_fops;
+		} else if (S_ISLNK(mode)) {
+			inode->i_op = &gfs2_symlink_iops;
+		} else {
+			inode->i_op = &gfs2_dev_iops;
+		}
+
+		error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
+		if (unlikely(error))
+			goto fail;
+		ip->i_gl->gl_object = ip;
+
+		error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
+		if (unlikely(error))
+			goto fail_put;
+
+		ip->i_vn = ip->i_gl->gl_vn - 1;
+		error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
+		if (unlikely(error))
+			goto fail_iopen;
+
+		gfs2_glock_put(io_gl);
+		unlock_new_inode(inode);
+	}
+
+	return inode;
+fail_iopen:
+	gfs2_glock_put(io_gl);
+fail_put:
+	ip->i_gl->gl_object = NULL;
+	gfs2_glock_put(ip->i_gl);
+fail:
+	iput(inode);
+	return ERR_PTR(error);
+}
+
+/**
+ * gfs2_inode_refresh - Refresh the incore copy of the dinode
+ * @ip: The GFS2 inode
+ *
+ * Returns: errno
+ */
+
+int gfs2_inode_refresh(struct gfs2_inode *ip)
+{
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		return error;
+
+	if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) {
+		brelse(dibh);
+		return -EIO;
+	}
+
+	gfs2_dinode_in(&ip->i_di, dibh->b_data);
+
+	brelse(dibh);
+
+	if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) {
+		if (gfs2_consist_inode(ip))
+			gfs2_dinode_print(&ip->i_di);
+		return -EIO;
+	}
+	if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino)
+		return -ESTALE;
+
+	ip->i_vn = ip->i_gl->gl_vn;
+
+	return 0;
+}
+
+int gfs2_dinode_dealloc(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al;
+	struct gfs2_rgrpd *rgd;
+	int error;
+
+	if (ip->i_di.di_blocks != 1) {
+		if (gfs2_consist_inode(ip))
+			gfs2_dinode_print(&ip->i_di);
+		return -EIO;
+	}
+
+	al = gfs2_alloc_get(ip);
+
+	error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out;
+
+	error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
+	if (error)
+		goto out_qs;
+
+	rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+	if (!rgd) {
+		gfs2_consist_inode(ip);
+		error = -EIO;
+		goto out_rindex_relse;
+	}
+
+	error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
+				   &al->al_rgd_gh);
+	if (error)
+		goto out_rindex_relse;
+
+	error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1);
+	if (error)
+		goto out_rg_gunlock;
+
+	gfs2_trans_add_gl(ip->i_gl);
+
+	gfs2_free_di(rgd, ip);
+
+	gfs2_trans_end(sdp);
+	clear_bit(GLF_STICKY, &ip->i_gl->gl_flags);
+
+out_rg_gunlock:
+	gfs2_glock_dq_uninit(&al->al_rgd_gh);
+out_rindex_relse:
+	gfs2_glock_dq_uninit(&al->al_ri_gh);
+out_qs:
+	gfs2_quota_unhold(ip);
+out:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
+/**
+ * gfs2_change_nlink - Change nlink count on inode
+ * @ip: The GFS2 inode
+ * @diff: The change in the nlink count required
+ *
+ * Returns: errno
+ */
+
+int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
+{
+	struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
+	struct buffer_head *dibh;
+	u32 nlink;
+	int error;
+
+	BUG_ON(ip->i_di.di_nlink != ip->i_inode.i_nlink);
+	nlink = ip->i_di.di_nlink + diff;
+
+	/* If we are reducing the nlink count, but the new value ends up being
+	   bigger than the old one, we must have underflowed. */
+	if (diff < 0 && nlink > ip->i_di.di_nlink) {
+		if (gfs2_consist_inode(ip))
+			gfs2_dinode_print(&ip->i_di);
+		return -EIO;
+	}
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		return error;
+
+	ip->i_di.di_nlink = nlink;
+	ip->i_di.di_ctime = get_seconds();
+	ip->i_inode.i_nlink = nlink;
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
+	mark_inode_dirty(&ip->i_inode);
+
+	if (ip->i_di.di_nlink == 0) {
+		struct gfs2_rgrpd *rgd;
+		struct gfs2_holder ri_gh, rg_gh;
+
+		error = gfs2_rindex_hold(sdp, &ri_gh);
+		if (error)
+			goto out;
+		error = -EIO;
+		rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+		if (!rgd)
+			goto out_norgrp;
+		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
+		if (error)
+			goto out_norgrp;
+
+		clear_nlink(&ip->i_inode);
+		gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
+		gfs2_glock_dq_uninit(&rg_gh);
+out_norgrp:
+		gfs2_glock_dq_uninit(&ri_gh);
+	}
+out:
+	return error;
+}
+
+struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
+{
+	struct qstr qstr;
+	gfs2_str2qstr(&qstr, name);
+	return gfs2_lookupi(dip, &qstr, 1, NULL);
+}
+
+
+/**
+ * gfs2_lookupi - Look up a filename in a directory and return its inode
+ * @d_gh: An initialized holder for the directory glock
+ * @name: The name of the inode to look for
+ * @is_root: If 1, ignore the caller's permissions
+ * @i_gh: An uninitialized holder for the new inode glock
+ *
+ * There will always be a vnode (Linux VFS inode) for the d_gh inode unless
+ * @is_root is true.
+ *
+ * Returns: errno
+ */
+
+struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
+			   int is_root, struct nameidata *nd)
+{
+	struct super_block *sb = dir->i_sb;
+	struct gfs2_inode *dip = GFS2_I(dir);
+	struct gfs2_holder d_gh;
+	struct gfs2_inum inum;
+	unsigned int type;
+	int error = 0;
+	struct inode *inode = NULL;
+
+	if (!name->len || name->len > GFS2_FNAMESIZE)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) ||
+	    (name->len == 2 && memcmp(name->name, "..", 2) == 0 &&
+	     dir == sb->s_root->d_inode)) {
+		igrab(dir);
+		return dir;
+	}
+
+	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+	if (error)
+		return ERR_PTR(error);
+
+	if (!is_root) {
+		error = permission(dir, MAY_EXEC, NULL);
+		if (error)
+			goto out;
+	}
+
+	error = gfs2_dir_search(dir, name, &inum, &type);
+	if (error)
+		goto out;
+
+	inode = gfs2_inode_lookup(sb, &inum, type);
+
+out:
+	gfs2_glock_dq_uninit(&d_gh);
+	if (error == -ENOENT)
+		return NULL;
+	return inode;
+}
+
+static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
+{
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
+	struct buffer_head *bh;
+	struct gfs2_inum_range ir;
+	int error;
+
+	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+	if (error)
+		return error;
+	mutex_lock(&sdp->sd_inum_mutex);
+
+	error = gfs2_meta_inode_buffer(ip, &bh);
+	if (error) {
+		mutex_unlock(&sdp->sd_inum_mutex);
+		gfs2_trans_end(sdp);
+		return error;
+	}
+
+	gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
+
+	if (ir.ir_length) {
+		*formal_ino = ir.ir_start++;
+		ir.ir_length--;
+		gfs2_trans_add_bh(ip->i_gl, bh, 1);
+		gfs2_inum_range_out(&ir,
+				    bh->b_data + sizeof(struct gfs2_dinode));
+		brelse(bh);
+		mutex_unlock(&sdp->sd_inum_mutex);
+		gfs2_trans_end(sdp);
+		return 0;
+	}
+
+	brelse(bh);
+
+	mutex_unlock(&sdp->sd_inum_mutex);
+	gfs2_trans_end(sdp);
+
+	return 1;
+}
+
+static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino)
+{
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
+	struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode);
+	struct gfs2_holder gh;
+	struct buffer_head *bh;
+	struct gfs2_inum_range ir;
+	int error;
+
+	error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+	if (error)
+		return error;
+
+	error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
+	if (error)
+		goto out;
+	mutex_lock(&sdp->sd_inum_mutex);
+
+	error = gfs2_meta_inode_buffer(ip, &bh);
+	if (error)
+		goto out_end_trans;
+
+	gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
+
+	if (!ir.ir_length) {
+		struct buffer_head *m_bh;
+		u64 x, y;
+
+		error = gfs2_meta_inode_buffer(m_ip, &m_bh);
+		if (error)
+			goto out_brelse;
+
+		x = *(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode));
+		x = y = be64_to_cpu(x);
+		ir.ir_start = x;
+		ir.ir_length = GFS2_INUM_QUANTUM;
+		x += GFS2_INUM_QUANTUM;
+		if (x < y)
+			gfs2_consist_inode(m_ip);
+		x = cpu_to_be64(x);
+		gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
+		*(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x;
+
+		brelse(m_bh);
+	}
+
+	*formal_ino = ir.ir_start++;
+	ir.ir_length--;
+
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+	gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode));
+
+out_brelse:
+	brelse(bh);
+out_end_trans:
+	mutex_unlock(&sdp->sd_inum_mutex);
+	gfs2_trans_end(sdp);
+out:
+	gfs2_glock_dq_uninit(&gh);
+	return error;
+}
+
+static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum)
+{
+	int error;
+
+	error = pick_formal_ino_1(sdp, inum);
+	if (error <= 0)
+		return error;
+
+	error = pick_formal_ino_2(sdp, inum);
+
+	return error;
+}
+
+/**
+ * create_ok - OK to create a new on-disk inode here?
+ * @dip:  Directory in which dinode is to be created
+ * @name:  Name of new dinode
+ * @mode:
+ *
+ * Returns: errno
+ */
+
+static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
+		     unsigned int mode)
+{
+	int error;
+
+	error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+	if (error)
+		return error;
+
+	/*  Don't create entries in an unlinked directory  */
+	if (!dip->i_di.di_nlink)
+		return -EPERM;
+
+	error = gfs2_dir_search(&dip->i_inode, name, NULL, NULL);
+	switch (error) {
+	case -ENOENT:
+		error = 0;
+		break;
+	case 0:
+		return -EEXIST;
+	default:
+		return error;
+	}
+
+	if (dip->i_di.di_entries == (u32)-1)
+		return -EFBIG;
+	if (S_ISDIR(mode) && dip->i_di.di_nlink == (u32)-1)
+		return -EMLINK;
+
+	return 0;
+}
+
+static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode,
+			       unsigned int *uid, unsigned int *gid)
+{
+	if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir &&
+	    (dip->i_di.di_mode & S_ISUID) && dip->i_di.di_uid) {
+		if (S_ISDIR(*mode))
+			*mode |= S_ISUID;
+		else if (dip->i_di.di_uid != current->fsuid)
+			*mode &= ~07111;
+		*uid = dip->i_di.di_uid;
+	} else
+		*uid = current->fsuid;
+
+	if (dip->i_di.di_mode & S_ISGID) {
+		if (S_ISDIR(*mode))
+			*mode |= S_ISGID;
+		*gid = dip->i_di.di_gid;
+	} else
+		*gid = current->fsgid;
+}
+
+static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum,
+			u64 *generation)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	int error;
+
+	gfs2_alloc_get(dip);
+
+	dip->i_alloc.al_requested = RES_DINODE;
+	error = gfs2_inplace_reserve(dip);
+	if (error)
+		goto out;
+
+	error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0);
+	if (error)
+		goto out_ipreserv;
+
+	inum->no_addr = gfs2_alloc_di(dip, generation);
+
+	gfs2_trans_end(sdp);
+
+out_ipreserv:
+	gfs2_inplace_release(dip);
+out:
+	gfs2_alloc_put(dip);
+	return error;
+}
+
+/**
+ * init_dinode - Fill in a new dinode structure
+ * @dip: the directory this inode is being created in
+ * @gl: The glock covering the new inode
+ * @inum: the inode number
+ * @mode: the file permissions
+ * @uid:
+ * @gid:
+ *
+ */
+
+static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
+			const struct gfs2_inum *inum, unsigned int mode,
+			unsigned int uid, unsigned int gid,
+			const u64 *generation)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct gfs2_dinode *di;
+	struct buffer_head *dibh;
+
+	dibh = gfs2_meta_new(gl, inum->no_addr);
+	gfs2_trans_add_bh(gl, dibh, 1);
+	gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI);
+	gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+	di = (struct gfs2_dinode *)dibh->b_data;
+
+	di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino);
+	di->di_num.no_addr = cpu_to_be64(inum->no_addr);
+	di->di_mode = cpu_to_be32(mode);
+	di->di_uid = cpu_to_be32(uid);
+	di->di_gid = cpu_to_be32(gid);
+	di->di_nlink = cpu_to_be32(0);
+	di->di_size = cpu_to_be64(0);
+	di->di_blocks = cpu_to_be64(1);
+	di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds());
+	di->di_major = di->di_minor = cpu_to_be32(0);
+	di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr);
+	di->di_generation = cpu_to_be64(*generation);
+	di->di_flags = cpu_to_be32(0);
+
+	if (S_ISREG(mode)) {
+		if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA) ||
+		    gfs2_tune_get(sdp, gt_new_files_jdata))
+			di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA);
+		if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO) ||
+		    gfs2_tune_get(sdp, gt_new_files_directio))
+			di->di_flags |= cpu_to_be32(GFS2_DIF_DIRECTIO);
+	} else if (S_ISDIR(mode)) {
+		di->di_flags |= cpu_to_be32(dip->i_di.di_flags &
+					    GFS2_DIF_INHERIT_DIRECTIO);
+		di->di_flags |= cpu_to_be32(dip->i_di.di_flags &
+					    GFS2_DIF_INHERIT_JDATA);
+	}
+
+	di->__pad1 = 0;
+	di->di_payload_format = cpu_to_be32(0);
+	di->di_height = cpu_to_be32(0);
+	di->__pad2 = 0;
+	di->__pad3 = 0;
+	di->di_depth = cpu_to_be16(0);
+	di->di_entries = cpu_to_be32(0);
+	memset(&di->__pad4, 0, sizeof(di->__pad4));
+	di->di_eattr = cpu_to_be64(0);
+	memset(&di->di_reserved, 0, sizeof(di->di_reserved));
+
+	brelse(dibh);
+}
+
+static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
+		       unsigned int mode, const struct gfs2_inum *inum,
+		       const u64 *generation)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	unsigned int uid, gid;
+	int error;
+
+	munge_mode_uid_gid(dip, &mode, &uid, &gid);
+	gfs2_alloc_get(dip);
+
+	error = gfs2_quota_lock(dip, uid, gid);
+	if (error)
+		goto out;
+
+	error = gfs2_quota_check(dip, uid, gid);
+	if (error)
+		goto out_quota;
+
+	error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0);
+	if (error)
+		goto out_quota;
+
+	init_dinode(dip, gl, inum, mode, uid, gid, generation);
+	gfs2_quota_change(dip, +1, uid, gid);
+	gfs2_trans_end(sdp);
+
+out_quota:
+	gfs2_quota_unlock(dip);
+out:
+	gfs2_alloc_put(dip);
+	return error;
+}
+
+static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
+		       struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct gfs2_alloc *al;
+	int alloc_required;
+	struct buffer_head *dibh;
+	int error;
+
+	al = gfs2_alloc_get(dip);
+
+	error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto fail;
+
+	error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name);
+	if (alloc_required < 0)
+		goto fail;
+	if (alloc_required) {
+		error = gfs2_quota_check(dip, dip->i_di.di_uid,
+					 dip->i_di.di_gid);
+		if (error)
+			goto fail_quota_locks;
+
+		al->al_requested = sdp->sd_max_dirres;
+
+		error = gfs2_inplace_reserve(dip);
+		if (error)
+			goto fail_quota_locks;
+
+		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
+					 al->al_rgd->rd_ri.ri_length +
+					 2 * RES_DINODE +
+					 RES_STATFS + RES_QUOTA, 0);
+		if (error)
+			goto fail_ipreserv;
+	} else {
+		error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0);
+		if (error)
+			goto fail_quota_locks;
+	}
+
+	error = gfs2_dir_add(&dip->i_inode, name, &ip->i_num, IF2DT(ip->i_di.di_mode));
+	if (error)
+		goto fail_end_trans;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto fail_end_trans;
+	ip->i_di.di_nlink = 1;
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
+	return 0;
+
+fail_end_trans:
+	gfs2_trans_end(sdp);
+
+fail_ipreserv:
+	if (dip->i_alloc.al_rgd)
+		gfs2_inplace_release(dip);
+
+fail_quota_locks:
+	gfs2_quota_unlock(dip);
+
+fail:
+	gfs2_alloc_put(dip);
+	return error;
+}
+
+static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
+{
+	int err;
+	size_t len;
+	void *value;
+	char *name;
+	struct gfs2_ea_request er;
+
+	err = security_inode_init_security(&ip->i_inode, &dip->i_inode,
+					   &name, &value, &len);
+
+	if (err) {
+		if (err == -EOPNOTSUPP)
+			return 0;
+		return err;
+	}
+
+	memset(&er, 0, sizeof(struct gfs2_ea_request));
+
+	er.er_type = GFS2_EATYPE_SECURITY;
+	er.er_name = name;
+	er.er_data = value;
+	er.er_name_len = strlen(name);
+	er.er_data_len = len;
+
+	err = gfs2_ea_set_i(ip, &er);
+
+	kfree(value);
+	kfree(name);
+
+	return err;
+}
+
+/**
+ * gfs2_createi - Create a new inode
+ * @ghs: An array of two holders
+ * @name: The name of the new file
+ * @mode: the permissions on the new inode
+ *
+ * @ghs[0] is an initialized holder for the directory
+ * @ghs[1] is the holder for the inode lock
+ *
+ * If the return value is not NULL, the glocks on both the directory and the new
+ * file are held.  A transaction has been started and an inplace reservation
+ * is held, as well.
+ *
+ * Returns: An inode
+ */
+
+struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
+			   unsigned int mode)
+{
+	struct inode *inode;
+	struct gfs2_inode *dip = ghs->gh_gl->gl_object;
+	struct inode *dir = &dip->i_inode;
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct gfs2_inum inum;
+	int error;
+	u64 generation;
+
+	if (!name->len || name->len > GFS2_FNAMESIZE)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
+	error = gfs2_glock_nq(ghs);
+	if (error)
+		goto fail;
+
+	error = create_ok(dip, name, mode);
+	if (error)
+		goto fail_gunlock;
+
+	error = pick_formal_ino(sdp, &inum.no_formal_ino);
+	if (error)
+		goto fail_gunlock;
+
+	error = alloc_dinode(dip, &inum, &generation);
+	if (error)
+		goto fail_gunlock;
+
+	if (inum.no_addr < dip->i_num.no_addr) {
+		gfs2_glock_dq(ghs);
+
+		error = gfs2_glock_nq_num(sdp, inum.no_addr,
+					  &gfs2_inode_glops, LM_ST_EXCLUSIVE,
+					  GL_SKIP, ghs + 1);
+		if (error) {
+			return ERR_PTR(error);
+		}
+
+		gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
+		error = gfs2_glock_nq(ghs);
+		if (error) {
+			gfs2_glock_dq_uninit(ghs + 1);
+			return ERR_PTR(error);
+		}
+
+		error = create_ok(dip, name, mode);
+		if (error)
+			goto fail_gunlock2;
+	} else {
+		error = gfs2_glock_nq_num(sdp, inum.no_addr,
+					  &gfs2_inode_glops, LM_ST_EXCLUSIVE,
+					  GL_SKIP, ghs + 1);
+		if (error)
+			goto fail_gunlock;
+	}
+
+	error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation);
+	if (error)
+		goto fail_gunlock2;
+
+	inode = gfs2_inode_lookup(dir->i_sb, &inum, IF2DT(mode));
+	if (IS_ERR(inode))
+		goto fail_gunlock2;
+
+	error = gfs2_inode_refresh(GFS2_I(inode));
+	if (error)
+		goto fail_iput;
+
+	error = gfs2_acl_create(dip, GFS2_I(inode));
+	if (error)
+		goto fail_iput;
+
+	error = gfs2_security_init(dip, GFS2_I(inode));
+	if (error)
+		goto fail_iput;
+
+	error = link_dinode(dip, name, GFS2_I(inode));
+	if (error)
+		goto fail_iput;
+
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+	return inode;
+
+fail_iput:
+	iput(inode);
+fail_gunlock2:
+	gfs2_glock_dq_uninit(ghs + 1);
+fail_gunlock:
+	gfs2_glock_dq(ghs);
+fail:
+	return ERR_PTR(error);
+}
+
+/**
+ * gfs2_rmdiri - Remove a directory
+ * @dip: The parent directory of the directory to be removed
+ * @name: The name of the directory to be removed
+ * @ip: The GFS2 inode of the directory to be removed
+ *
+ * Assumes Glocks on dip and ip are held
+ *
+ * Returns: errno
+ */
+
+int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
+		struct gfs2_inode *ip)
+{
+	struct qstr dotname;
+	int error;
+
+	if (ip->i_di.di_entries != 2) {
+		if (gfs2_consist_inode(ip))
+			gfs2_dinode_print(&ip->i_di);
+		return -EIO;
+	}
+
+	error = gfs2_dir_del(dip, name);
+	if (error)
+		return error;
+
+	error = gfs2_change_nlink(dip, -1);
+	if (error)
+		return error;
+
+	gfs2_str2qstr(&dotname, ".");
+	error = gfs2_dir_del(ip, &dotname);
+	if (error)
+		return error;
+
+	gfs2_str2qstr(&dotname, "..");
+	error = gfs2_dir_del(ip, &dotname);
+	if (error)
+		return error;
+
+	error = gfs2_change_nlink(ip, -2);
+	if (error)
+		return error;
+
+	return error;
+}
+
+/*
+ * gfs2_unlink_ok - check to see that a inode is still in a directory
+ * @dip: the directory
+ * @name: the name of the file
+ * @ip: the inode
+ *
+ * Assumes that the lock on (at least) @dip is held.
+ *
+ * Returns: 0 if the parent/child relationship is correct, errno if it isn't
+ */
+
+int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
+		   struct gfs2_inode *ip)
+{
+	struct gfs2_inum inum;
+	unsigned int type;
+	int error;
+
+	if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
+		return -EPERM;
+
+	if ((dip->i_di.di_mode & S_ISVTX) &&
+	    dip->i_di.di_uid != current->fsuid &&
+	    ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER))
+		return -EPERM;
+
+	if (IS_APPEND(&dip->i_inode))
+		return -EPERM;
+
+	error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+	if (error)
+		return error;
+
+	error = gfs2_dir_search(&dip->i_inode, name, &inum, &type);
+	if (error)
+		return error;
+
+	if (!gfs2_inum_equal(&inum, &ip->i_num))
+		return -ENOENT;
+
+	if (IF2DT(ip->i_di.di_mode) != type) {
+		gfs2_consist_inode(dip);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * gfs2_ok_to_move - check if it's ok to move a directory to another directory
+ * @this: move this
+ * @to: to here
+ *
+ * Follow @to back to the root and make sure we don't encounter @this
+ * Assumes we already hold the rename lock.
+ *
+ * Returns: errno
+ */
+
+int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
+{
+	struct inode *dir = &to->i_inode;
+	struct super_block *sb = dir->i_sb;
+	struct inode *tmp;
+	struct qstr dotdot;
+	int error = 0;
+
+	gfs2_str2qstr(&dotdot, "..");
+
+	igrab(dir);
+
+	for (;;) {
+		if (dir == &this->i_inode) {
+			error = -EINVAL;
+			break;
+		}
+		if (dir == sb->s_root->d_inode) {
+			error = 0;
+			break;
+		}
+
+		tmp = gfs2_lookupi(dir, &dotdot, 1, NULL);
+		if (IS_ERR(tmp)) {
+			error = PTR_ERR(tmp);
+			break;
+		}
+
+		iput(dir);
+		dir = tmp;
+	}
+
+	iput(dir);
+
+	return error;
+}
+
+/**
+ * gfs2_readlinki - return the contents of a symlink
+ * @ip: the symlink's inode
+ * @buf: a pointer to the buffer to be filled
+ * @len: a pointer to the length of @buf
+ *
+ * If @buf is too small, a piece of memory is kmalloc()ed and needs
+ * to be freed by the caller.
+ *
+ * Returns: errno
+ */
+
+int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
+{
+	struct gfs2_holder i_gh;
+	struct buffer_head *dibh;
+	unsigned int x;
+	int error;
+
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh);
+	error = gfs2_glock_nq_atime(&i_gh);
+	if (error) {
+		gfs2_holder_uninit(&i_gh);
+		return error;
+	}
+
+	if (!ip->i_di.di_size) {
+		gfs2_consist_inode(ip);
+		error = -EIO;
+		goto out;
+	}
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto out;
+
+	x = ip->i_di.di_size + 1;
+	if (x > *len) {
+		*buf = kmalloc(x, GFP_KERNEL);
+		if (!*buf) {
+			error = -ENOMEM;
+			goto out_brelse;
+		}
+	}
+
+	memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
+	*len = x;
+
+out_brelse:
+	brelse(dibh);
+out:
+	gfs2_glock_dq_uninit(&i_gh);
+	return error;
+}
+
+/**
+ * gfs2_glock_nq_atime - Acquire a hold on an inode's glock, and
+ *       conditionally update the inode's atime
+ * @gh: the holder to acquire
+ *
+ * Tests atime (access time) for gfs2_read, gfs2_readdir and gfs2_mmap
+ * Update if the difference between the current time and the inode's current
+ * atime is greater than an interval specified at mount.
+ *
+ * Returns: errno
+ */
+
+int gfs2_glock_nq_atime(struct gfs2_holder *gh)
+{
+	struct gfs2_glock *gl = gh->gh_gl;
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	struct gfs2_inode *ip = gl->gl_object;
+	s64 curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum);
+	unsigned int state;
+	int flags;
+	int error;
+
+	if (gfs2_assert_warn(sdp, gh->gh_flags & GL_ATIME) ||
+	    gfs2_assert_warn(sdp, !(gh->gh_flags & GL_ASYNC)) ||
+	    gfs2_assert_warn(sdp, gl->gl_ops == &gfs2_inode_glops))
+		return -EINVAL;
+
+	state = gh->gh_state;
+	flags = gh->gh_flags;
+
+	error = gfs2_glock_nq(gh);
+	if (error)
+		return error;
+
+	if (test_bit(SDF_NOATIME, &sdp->sd_flags) ||
+	    (sdp->sd_vfs->s_flags & MS_RDONLY))
+		return 0;
+
+	curtime = get_seconds();
+	if (curtime - ip->i_di.di_atime >= quantum) {
+		gfs2_glock_dq(gh);
+		gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY,
+				   gh);
+		error = gfs2_glock_nq(gh);
+		if (error)
+			return error;
+
+		/* Verify that atime hasn't been updated while we were
+		   trying to get exclusive lock. */
+
+		curtime = get_seconds();
+		if (curtime - ip->i_di.di_atime >= quantum) {
+			struct buffer_head *dibh;
+			struct gfs2_dinode *di;
+
+			error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+			if (error == -EROFS)
+				return 0;
+			if (error)
+				goto fail;
+
+			error = gfs2_meta_inode_buffer(ip, &dibh);
+			if (error)
+				goto fail_end_trans;
+
+			ip->i_di.di_atime = curtime;
+
+			gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+			di = (struct gfs2_dinode *)dibh->b_data;
+			di->di_atime = cpu_to_be64(ip->i_di.di_atime);
+			brelse(dibh);
+
+			gfs2_trans_end(sdp);
+		}
+
+		/* If someone else has asked for the glock,
+		   unlock and let them have it. Then reacquire
+		   in the original state. */
+		if (gfs2_glock_is_blocking(gl)) {
+			gfs2_glock_dq(gh);
+			gfs2_holder_reinit(state, flags, gh);
+			return gfs2_glock_nq(gh);
+		}
+	}
+
+	return 0;
+
+fail_end_trans:
+	gfs2_trans_end(sdp);
+fail:
+	gfs2_glock_dq(gh);
+	return error;
+}
+
+/**
+ * glock_compare_atime - Compare two struct gfs2_glock structures for sort
+ * @arg_a: the first structure
+ * @arg_b: the second structure
+ *
+ * Returns: 1 if A > B
+ *         -1 if A < B
+ *          0 if A == B
+ */
+
+static int glock_compare_atime(const void *arg_a, const void *arg_b)
+{
+	const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a;
+	const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b;
+	const struct lm_lockname *a = &gh_a->gh_gl->gl_name;
+	const struct lm_lockname *b = &gh_b->gh_gl->gl_name;
+
+	if (a->ln_number > b->ln_number)
+		return 1;
+	if (a->ln_number < b->ln_number)
+		return -1;
+	if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
+		return 1;
+	if (gh_a->gh_state == LM_ST_SHARED && (gh_b->gh_flags & GL_ATIME))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * gfs2_glock_nq_m_atime - acquire multiple glocks where one may need an
+ *      atime update
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ * Returns: 0 on success (all glocks acquired),
+ *          errno on failure (no glocks acquired)
+ */
+
+int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+	struct gfs2_holder **p;
+	unsigned int x;
+	int error = 0;
+
+	if (!num_gh)
+		return 0;
+
+	if (num_gh == 1) {
+		ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+		if (ghs->gh_flags & GL_ATIME)
+			error = gfs2_glock_nq_atime(ghs);
+		else
+			error = gfs2_glock_nq(ghs);
+		return error;
+	}
+
+	p = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	for (x = 0; x < num_gh; x++)
+		p[x] = &ghs[x];
+
+	sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare_atime,NULL);
+
+	for (x = 0; x < num_gh; x++) {
+		p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+
+		if (p[x]->gh_flags & GL_ATIME)
+			error = gfs2_glock_nq_atime(p[x]);
+		else
+			error = gfs2_glock_nq(p[x]);
+
+		if (error) {
+			while (x--)
+				gfs2_glock_dq(p[x]);
+			break;
+		}
+	}
+
+	kfree(p);
+	return error;
+}
+
+
+static int
+__gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+{
+	struct buffer_head *dibh;
+	int error;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (!error) {
+		error = inode_setattr(&ip->i_inode, attr);
+		gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
+		gfs2_inode_attr_out(ip);
+
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+	return error;
+}
+
+/**
+ * gfs2_setattr_simple -
+ * @ip:
+ * @attr:
+ *
+ * Called with a reference on the vnode.
+ *
+ * Returns: errno
+ */
+
+int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+{
+	int error;
+
+	if (current->journal_info)
+		return __gfs2_setattr_simple(ip, attr);
+
+	error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
+	if (error)
+		return error;
+
+	error = __gfs2_setattr_simple(ip, attr);
+	gfs2_trans_end(GFS2_SB(&ip->i_inode));
+	return error;
+}
+
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
new file mode 100644
index 0000000..f5d8617
--- /dev/null
+++ b/fs/gfs2/inode.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __INODE_DOT_H__
+#define __INODE_DOT_H__
+
+static inline int gfs2_is_stuffed(struct gfs2_inode *ip)
+{
+	return !ip->i_di.di_height;
+}
+
+static inline int gfs2_is_jdata(struct gfs2_inode *ip)
+{
+	return ip->i_di.di_flags & GFS2_DIF_JDATA;
+}
+
+static inline int gfs2_is_dir(struct gfs2_inode *ip)
+{
+	return S_ISDIR(ip->i_di.di_mode);
+}
+
+void gfs2_inode_attr_in(struct gfs2_inode *ip);
+void gfs2_inode_attr_out(struct gfs2_inode *ip);
+struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned type);
+struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum);
+
+int gfs2_inode_refresh(struct gfs2_inode *ip);
+
+int gfs2_dinode_dealloc(struct gfs2_inode *inode);
+int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
+struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
+			   int is_root, struct nameidata *nd);
+struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
+			   unsigned int mode);
+int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
+		struct gfs2_inode *ip);
+int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
+		   struct gfs2_inode *ip);
+int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to);
+int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len);
+
+int gfs2_glock_nq_atime(struct gfs2_holder *gh);
+int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs);
+
+int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
+
+struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
+
+#endif /* __INODE_DOT_H__ */
+
diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c
new file mode 100644
index 0000000..effe4a3
--- /dev/null
+++ b/fs/gfs2/lm.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/delay.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "lm.h"
+#include "super.h"
+#include "util.h"
+
+/**
+ * gfs2_lm_mount - mount a locking protocol
+ * @sdp: the filesystem
+ * @args: mount arguements
+ * @silent: if 1, don't complain if the FS isn't a GFS2 fs
+ *
+ * Returns: errno
+ */
+
+int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
+{
+	char *proto = sdp->sd_proto_name;
+	char *table = sdp->sd_table_name;
+	int flags = 0;
+	int error;
+
+	if (sdp->sd_args.ar_spectator)
+		flags |= LM_MFLAG_SPECTATOR;
+
+	fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
+
+	error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata,
+				     gfs2_glock_cb, sdp,
+				     GFS2_MIN_LVB_SIZE, flags,
+				     &sdp->sd_lockstruct, &sdp->sd_kobj);
+	if (error) {
+		fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n",
+			proto, table, sdp->sd_args.ar_hostdata);
+		goto out;
+	}
+
+	if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) ||
+	    gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) ||
+	    gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >=
+				  GFS2_MIN_LVB_SIZE)) {
+		gfs2_unmount_lockproto(&sdp->sd_lockstruct);
+		goto out;
+	}
+
+	if (sdp->sd_args.ar_spectator)
+		snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table);
+	else
+		snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
+			 sdp->sd_lockstruct.ls_jid);
+
+	fs_info(sdp, "Joined cluster. Now mounting FS...\n");
+
+	if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) &&
+	    !sdp->sd_args.ar_ignore_local_fs) {
+		sdp->sd_args.ar_localflocks = 1;
+		sdp->sd_args.ar_localcaching = 1;
+	}
+
+out:
+	return error;
+}
+
+void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp)
+{
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		sdp->sd_lockstruct.ls_ops->lm_others_may_mount(
+					sdp->sd_lockstruct.ls_lockspace);
+}
+
+void gfs2_lm_unmount(struct gfs2_sbd *sdp)
+{
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		gfs2_unmount_lockproto(&sdp->sd_lockstruct);
+}
+
+int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
+{
+	va_list args;
+
+	if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+		return 0;
+
+	va_start(args, fmt);
+	vprintk(fmt, args);
+	va_end(args);
+
+	fs_err(sdp, "about to withdraw from the cluster\n");
+	BUG_ON(sdp->sd_args.ar_debug);
+
+
+	fs_err(sdp, "waiting for outstanding I/O\n");
+
+	/* FIXME: suspend dm device so oustanding bio's complete
+	   and all further io requests fail */
+
+	fs_err(sdp, "telling LM to withdraw\n");
+	gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
+	fs_err(sdp, "withdrawn\n");
+	dump_stack();
+
+	return -1;
+}
+
+int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		     void **lockp)
+{
+	int error = -EIO;
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		error = sdp->sd_lockstruct.ls_ops->lm_get_lock(
+				sdp->sd_lockstruct.ls_lockspace, name, lockp);
+	return error;
+}
+
+void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock)
+{
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		sdp->sd_lockstruct.ls_ops->lm_put_lock(lock);
+}
+
+unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
+			  unsigned int cur_state, unsigned int req_state,
+			  unsigned int flags)
+{
+	int ret = 0;
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state,
+							 req_state, flags);
+	return ret;
+}
+
+unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
+			    unsigned int cur_state)
+{
+	int ret = 0;
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		ret =  sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state);
+	return ret;
+}
+
+void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock)
+{
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		sdp->sd_lockstruct.ls_ops->lm_cancel(lock);
+}
+
+int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp)
+{
+	int error = -EIO;
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp);
+	return error;
+}
+
+void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb)
+{
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb);
+}
+
+int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		      struct file *file, struct file_lock *fl)
+{
+	int error = -EIO;
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		error = sdp->sd_lockstruct.ls_ops->lm_plock_get(
+				sdp->sd_lockstruct.ls_lockspace, name, file, fl);
+	return error;
+}
+
+int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		  struct file *file, int cmd, struct file_lock *fl)
+{
+	int error = -EIO;
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		error = sdp->sd_lockstruct.ls_ops->lm_plock(
+				sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl);
+	return error;
+}
+
+int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		    struct file *file, struct file_lock *fl)
+{
+	int error = -EIO;
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		error = sdp->sd_lockstruct.ls_ops->lm_punlock(
+				sdp->sd_lockstruct.ls_lockspace, name, file, fl);
+	return error;
+}
+
+void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
+			   unsigned int message)
+{
+	if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		sdp->sd_lockstruct.ls_ops->lm_recovery_done(
+			sdp->sd_lockstruct.ls_lockspace, jid, message);
+}
+
diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h
new file mode 100644
index 0000000..21cdc30
--- /dev/null
+++ b/fs/gfs2/lm.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LM_DOT_H__
+#define __LM_DOT_H__
+
+struct gfs2_sbd;
+
+#define GFS2_MIN_LVB_SIZE 32
+
+int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent);
+void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp);
+void gfs2_lm_unmount(struct gfs2_sbd *sdp);
+int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
+				__attribute__ ((format(printf, 2, 3)));
+int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		     void **lockp);
+void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock);
+unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
+			 unsigned int cur_state, unsigned int req_state,
+			 unsigned int flags);
+unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
+			   unsigned int cur_state);
+void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock);
+int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp);
+void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb);
+int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		      struct file *file, struct file_lock *fl);
+int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		  struct file *file, int cmd, struct file_lock *fl);
+int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+		    struct file *file, struct file_lock *fl);
+void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
+			   unsigned int message);
+
+#endif /* __LM_DOT_H__ */
diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c
new file mode 100644
index 0000000..663fee7
--- /dev/null
+++ b/fs/gfs2/locking.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/lm_interface.h>
+
+struct lmh_wrapper {
+	struct list_head lw_list;
+	const struct lm_lockops *lw_ops;
+};
+
+/* List of registered low-level locking protocols.  A file system selects one
+   of them by name at mount time, e.g. lock_nolock, lock_dlm. */
+
+static LIST_HEAD(lmh_list);
+static DEFINE_MUTEX(lmh_lock);
+
+/**
+ * gfs2_register_lockproto - Register a low-level locking protocol
+ * @proto: the protocol definition
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+int gfs2_register_lockproto(const struct lm_lockops *proto)
+{
+	struct lmh_wrapper *lw;
+
+	mutex_lock(&lmh_lock);
+
+	list_for_each_entry(lw, &lmh_list, lw_list) {
+		if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
+			mutex_unlock(&lmh_lock);
+			printk(KERN_INFO "GFS2: protocol %s already exists\n",
+			       proto->lm_proto_name);
+			return -EEXIST;
+		}
+	}
+
+	lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL);
+	if (!lw) {
+		mutex_unlock(&lmh_lock);
+		return -ENOMEM;
+	}
+
+	lw->lw_ops = proto;
+	list_add(&lw->lw_list, &lmh_list);
+
+	mutex_unlock(&lmh_lock);
+
+	return 0;
+}
+
+/**
+ * gfs2_unregister_lockproto - Unregister a low-level locking protocol
+ * @proto: the protocol definition
+ *
+ */
+
+void gfs2_unregister_lockproto(const struct lm_lockops *proto)
+{
+	struct lmh_wrapper *lw;
+
+	mutex_lock(&lmh_lock);
+
+	list_for_each_entry(lw, &lmh_list, lw_list) {
+		if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
+			list_del(&lw->lw_list);
+			mutex_unlock(&lmh_lock);
+			kfree(lw);
+			return;
+		}
+	}
+
+	mutex_unlock(&lmh_lock);
+
+	printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n",
+	       proto->lm_proto_name);
+}
+
+/**
+ * gfs2_mount_lockproto - Mount a lock protocol
+ * @proto_name - the name of the protocol
+ * @table_name - the name of the lock space
+ * @host_data - data specific to this host
+ * @cb - the callback to the code using the lock module
+ * @sdp - The GFS2 superblock
+ * @min_lvb_size - the mininum LVB size that the caller can deal with
+ * @flags - LM_MFLAG_*
+ * @lockstruct - a structure returned describing the mount
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
+			 lm_callback_t cb, void *cb_data,
+			 unsigned int min_lvb_size, int flags,
+			 struct lm_lockstruct *lockstruct,
+			 struct kobject *fskobj)
+{
+	struct lmh_wrapper *lw = NULL;
+	int try = 0;
+	int error, found;
+
+retry:
+	mutex_lock(&lmh_lock);
+
+	found = 0;
+	list_for_each_entry(lw, &lmh_list, lw_list) {
+		if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		if (!try && capable(CAP_SYS_MODULE)) {
+			try = 1;
+			mutex_unlock(&lmh_lock);
+			request_module(proto_name);
+			goto retry;
+		}
+		printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name);
+		error = -ENOENT;
+		goto out;
+	}
+
+	if (!try_module_get(lw->lw_ops->lm_owner)) {
+		try = 0;
+		mutex_unlock(&lmh_lock);
+		msleep(1000);
+		goto retry;
+	}
+
+	error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data,
+				     min_lvb_size, flags, lockstruct, fskobj);
+	if (error)
+		module_put(lw->lw_ops->lm_owner);
+out:
+	mutex_unlock(&lmh_lock);
+	return error;
+}
+
+void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct)
+{
+	mutex_lock(&lmh_lock);
+	lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace);
+	if (lockstruct->ls_ops->lm_owner)
+		module_put(lockstruct->ls_ops->lm_owner);
+	mutex_unlock(&lmh_lock);
+}
+
+/**
+ * gfs2_withdraw_lockproto - abnormally unmount a lock module
+ * @lockstruct: the lockstruct passed into mount
+ *
+ */
+
+void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct)
+{
+	mutex_lock(&lmh_lock);
+	lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace);
+	if (lockstruct->ls_ops->lm_owner)
+		module_put(lockstruct->ls_ops->lm_owner);
+	mutex_unlock(&lmh_lock);
+}
+
+EXPORT_SYMBOL_GPL(gfs2_register_lockproto);
+EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto);
+
diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile
new file mode 100644
index 0000000..89b93b6b
--- /dev/null
+++ b/fs/gfs2/locking/dlm/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
+lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o plock.o
+
diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c
new file mode 100644
index 0000000..b167add
--- /dev/null
+++ b/fs/gfs2/locking/dlm/lock.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include "lock_dlm.h"
+
+static char junk_lvb[GDLM_LVB_SIZE];
+
+static void queue_complete(struct gdlm_lock *lp)
+{
+	struct gdlm_ls *ls = lp->ls;
+
+	clear_bit(LFL_ACTIVE, &lp->flags);
+
+	spin_lock(&ls->async_lock);
+	list_add_tail(&lp->clist, &ls->complete);
+	spin_unlock(&ls->async_lock);
+	wake_up(&ls->thread_wait);
+}
+
+static inline void gdlm_ast(void *astarg)
+{
+	queue_complete(astarg);
+}
+
+static inline void gdlm_bast(void *astarg, int mode)
+{
+	struct gdlm_lock *lp = astarg;
+	struct gdlm_ls *ls = lp->ls;
+
+	if (!mode) {
+		printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n",
+			lp->lockname.ln_type,
+			(unsigned long long)lp->lockname.ln_number);
+		return;
+	}
+
+	spin_lock(&ls->async_lock);
+	if (!lp->bast_mode) {
+		list_add_tail(&lp->blist, &ls->blocking);
+		lp->bast_mode = mode;
+	} else if (lp->bast_mode < mode)
+		lp->bast_mode = mode;
+	spin_unlock(&ls->async_lock);
+	wake_up(&ls->thread_wait);
+}
+
+void gdlm_queue_delayed(struct gdlm_lock *lp)
+{
+	struct gdlm_ls *ls = lp->ls;
+
+	spin_lock(&ls->async_lock);
+	list_add_tail(&lp->delay_list, &ls->delayed);
+	spin_unlock(&ls->async_lock);
+}
+
+/* convert gfs lock-state to dlm lock-mode */
+
+static s16 make_mode(s16 lmstate)
+{
+	switch (lmstate) {
+	case LM_ST_UNLOCKED:
+		return DLM_LOCK_NL;
+	case LM_ST_EXCLUSIVE:
+		return DLM_LOCK_EX;
+	case LM_ST_DEFERRED:
+		return DLM_LOCK_CW;
+	case LM_ST_SHARED:
+		return DLM_LOCK_PR;
+	}
+	gdlm_assert(0, "unknown LM state %d", lmstate);
+	return -1;
+}
+
+/* convert dlm lock-mode to gfs lock-state */
+
+s16 gdlm_make_lmstate(s16 dlmmode)
+{
+	switch (dlmmode) {
+	case DLM_LOCK_IV:
+	case DLM_LOCK_NL:
+		return LM_ST_UNLOCKED;
+	case DLM_LOCK_EX:
+		return LM_ST_EXCLUSIVE;
+	case DLM_LOCK_CW:
+		return LM_ST_DEFERRED;
+	case DLM_LOCK_PR:
+		return LM_ST_SHARED;
+	}
+	gdlm_assert(0, "unknown DLM mode %d", dlmmode);
+	return -1;
+}
+
+/* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and
+   DLM_LOCK_IV are both considered LM_ST_UNLOCKED by GFS. */
+
+static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state)
+{
+	s16 cur = make_mode(cur_state);
+	if (lp->cur != DLM_LOCK_IV)
+		gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur);
+}
+
+static inline unsigned int make_flags(struct gdlm_lock *lp,
+				      unsigned int gfs_flags,
+				      s16 cur, s16 req)
+{
+	unsigned int lkf = 0;
+
+	if (gfs_flags & LM_FLAG_TRY)
+		lkf |= DLM_LKF_NOQUEUE;
+
+	if (gfs_flags & LM_FLAG_TRY_1CB) {
+		lkf |= DLM_LKF_NOQUEUE;
+		lkf |= DLM_LKF_NOQUEUEBAST;
+	}
+
+	if (gfs_flags & LM_FLAG_PRIORITY) {
+		lkf |= DLM_LKF_NOORDER;
+		lkf |= DLM_LKF_HEADQUE;
+	}
+
+	if (gfs_flags & LM_FLAG_ANY) {
+		if (req == DLM_LOCK_PR)
+			lkf |= DLM_LKF_ALTCW;
+		else if (req == DLM_LOCK_CW)
+			lkf |= DLM_LKF_ALTPR;
+	}
+
+	if (lp->lksb.sb_lkid != 0) {
+		lkf |= DLM_LKF_CONVERT;
+
+		/* Conversion deadlock avoidance by DLM */
+
+		if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) &&
+		    !(lkf & DLM_LKF_NOQUEUE) &&
+		    cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req)
+			lkf |= DLM_LKF_CONVDEADLK;
+	}
+
+	if (lp->lvb)
+		lkf |= DLM_LKF_VALBLK;
+
+	return lkf;
+}
+
+/* make_strname - convert GFS lock numbers to a string */
+
+static inline void make_strname(struct lm_lockname *lockname,
+				struct gdlm_strname *str)
+{
+	sprintf(str->name, "%8x%16llx", lockname->ln_type,
+		(unsigned long long)lockname->ln_number);
+	str->namelen = GDLM_STRNAME_BYTES;
+}
+
+static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
+			  struct gdlm_lock **lpp)
+{
+	struct gdlm_lock *lp;
+
+	lp = kzalloc(sizeof(struct gdlm_lock), GFP_KERNEL);
+	if (!lp)
+		return -ENOMEM;
+
+	lp->lockname = *name;
+	lp->ls = ls;
+	lp->cur = DLM_LOCK_IV;
+	lp->lvb = NULL;
+	lp->hold_null = NULL;
+	init_completion(&lp->ast_wait);
+	INIT_LIST_HEAD(&lp->clist);
+	INIT_LIST_HEAD(&lp->blist);
+	INIT_LIST_HEAD(&lp->delay_list);
+
+	spin_lock(&ls->async_lock);
+	list_add(&lp->all_list, &ls->all_locks);
+	ls->all_locks_count++;
+	spin_unlock(&ls->async_lock);
+
+	*lpp = lp;
+	return 0;
+}
+
+void gdlm_delete_lp(struct gdlm_lock *lp)
+{
+	struct gdlm_ls *ls = lp->ls;
+
+	spin_lock(&ls->async_lock);
+	if (!list_empty(&lp->clist))
+		list_del_init(&lp->clist);
+	if (!list_empty(&lp->blist))
+		list_del_init(&lp->blist);
+	if (!list_empty(&lp->delay_list))
+		list_del_init(&lp->delay_list);
+	gdlm_assert(!list_empty(&lp->all_list), "%x,%llx", lp->lockname.ln_type,
+		    (unsigned long long)lp->lockname.ln_number);
+	list_del_init(&lp->all_list);
+	ls->all_locks_count--;
+	spin_unlock(&ls->async_lock);
+
+	kfree(lp);
+}
+
+int gdlm_get_lock(void *lockspace, struct lm_lockname *name,
+		  void **lockp)
+{
+	struct gdlm_lock *lp;
+	int error;
+
+	error = gdlm_create_lp(lockspace, name, &lp);
+
+	*lockp = lp;
+	return error;
+}
+
+void gdlm_put_lock(void *lock)
+{
+	gdlm_delete_lp(lock);
+}
+
+unsigned int gdlm_do_lock(struct gdlm_lock *lp)
+{
+	struct gdlm_ls *ls = lp->ls;
+	struct gdlm_strname str;
+	int error, bast = 1;
+
+	/*
+	 * When recovery is in progress, delay lock requests for submission
+	 * once recovery is done.  Requests for recovery (NOEXP) and unlocks
+	 * can pass.
+	 */
+
+	if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
+	    !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) {
+		gdlm_queue_delayed(lp);
+		return LM_OUT_ASYNC;
+	}
+
+	/*
+	 * Submit the actual lock request.
+	 */
+
+	if (test_bit(LFL_NOBAST, &lp->flags))
+		bast = 0;
+
+	make_strname(&lp->lockname, &str);
+
+	set_bit(LFL_ACTIVE, &lp->flags);
+
+	log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type,
+		  (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid,
+		  lp->cur, lp->req, lp->lkf);
+
+	error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf,
+			 str.name, str.namelen, 0, gdlm_ast, lp,
+			 bast ? gdlm_bast : NULL);
+
+	if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
+		lp->lksb.sb_status = -EAGAIN;
+		queue_complete(lp);
+		error = 0;
+	}
+
+	if (error) {
+		log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
+			  "flags=%lx", ls->fsname, lp->lockname.ln_type,
+			  (unsigned long long)lp->lockname.ln_number, error,
+			  lp->cur, lp->req, lp->lkf, lp->flags);
+		return LM_OUT_ERROR;
+	}
+	return LM_OUT_ASYNC;
+}
+
+static unsigned int gdlm_do_unlock(struct gdlm_lock *lp)
+{
+	struct gdlm_ls *ls = lp->ls;
+	unsigned int lkf = 0;
+	int error;
+
+	set_bit(LFL_DLM_UNLOCK, &lp->flags);
+	set_bit(LFL_ACTIVE, &lp->flags);
+
+	if (lp->lvb)
+		lkf = DLM_LKF_VALBLK;
+
+	log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type,
+		  (unsigned long long)lp->lockname.ln_number,
+		  lp->lksb.sb_lkid, lp->cur, lkf);
+
+	error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp);
+
+	if (error) {
+		log_debug("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
+			  "flags=%lx", ls->fsname, lp->lockname.ln_type,
+			  (unsigned long long)lp->lockname.ln_number, error,
+			  lp->cur, lp->req, lp->lkf, lp->flags);
+		return LM_OUT_ERROR;
+	}
+	return LM_OUT_ASYNC;
+}
+
+unsigned int gdlm_lock(void *lock, unsigned int cur_state,
+		       unsigned int req_state, unsigned int flags)
+{
+	struct gdlm_lock *lp = lock;
+
+	clear_bit(LFL_DLM_CANCEL, &lp->flags);
+	if (flags & LM_FLAG_NOEXP)
+		set_bit(LFL_NOBLOCK, &lp->flags);
+
+	check_cur_state(lp, cur_state);
+	lp->req = make_mode(req_state);
+	lp->lkf = make_flags(lp, flags, lp->cur, lp->req);
+
+	return gdlm_do_lock(lp);
+}
+
+unsigned int gdlm_unlock(void *lock, unsigned int cur_state)
+{
+	struct gdlm_lock *lp = lock;
+
+	clear_bit(LFL_DLM_CANCEL, &lp->flags);
+	if (lp->cur == DLM_LOCK_IV)
+		return 0;
+	return gdlm_do_unlock(lp);
+}
+
+void gdlm_cancel(void *lock)
+{
+	struct gdlm_lock *lp = lock;
+	struct gdlm_ls *ls = lp->ls;
+	int error, delay_list = 0;
+
+	if (test_bit(LFL_DLM_CANCEL, &lp->flags))
+		return;
+
+	log_info("gdlm_cancel %x,%llx flags %lx", lp->lockname.ln_type,
+		 (unsigned long long)lp->lockname.ln_number, lp->flags);
+
+	spin_lock(&ls->async_lock);
+	if (!list_empty(&lp->delay_list)) {
+		list_del_init(&lp->delay_list);
+		delay_list = 1;
+	}
+	spin_unlock(&ls->async_lock);
+
+	if (delay_list) {
+		set_bit(LFL_CANCEL, &lp->flags);
+		set_bit(LFL_ACTIVE, &lp->flags);
+		queue_complete(lp);
+		return;
+	}
+
+	if (!test_bit(LFL_ACTIVE, &lp->flags) ||
+	    test_bit(LFL_DLM_UNLOCK, &lp->flags)) {
+		log_info("gdlm_cancel skip %x,%llx flags %lx",
+		 	 lp->lockname.ln_type,
+			 (unsigned long long)lp->lockname.ln_number, lp->flags);
+		return;
+	}
+
+	/* the lock is blocked in the dlm */
+
+	set_bit(LFL_DLM_CANCEL, &lp->flags);
+	set_bit(LFL_ACTIVE, &lp->flags);
+
+	error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, DLM_LKF_CANCEL,
+			   NULL, lp);
+
+	log_info("gdlm_cancel rv %d %x,%llx flags %lx", error,
+		 lp->lockname.ln_type,
+		 (unsigned long long)lp->lockname.ln_number, lp->flags);
+
+	if (error == -EBUSY)
+		clear_bit(LFL_DLM_CANCEL, &lp->flags);
+}
+
+static int gdlm_add_lvb(struct gdlm_lock *lp)
+{
+	char *lvb;
+
+	lvb = kzalloc(GDLM_LVB_SIZE, GFP_KERNEL);
+	if (!lvb)
+		return -ENOMEM;
+
+	lp->lksb.sb_lvbptr = lvb;
+	lp->lvb = lvb;
+	return 0;
+}
+
+static void gdlm_del_lvb(struct gdlm_lock *lp)
+{
+	kfree(lp->lvb);
+	lp->lvb = NULL;
+	lp->lksb.sb_lvbptr = NULL;
+}
+
+/* This can do a synchronous dlm request (requiring a lock_dlm thread to get
+   the completion) because gfs won't call hold_lvb() during a callback (from
+   the context of a lock_dlm thread). */
+
+static int hold_null_lock(struct gdlm_lock *lp)
+{
+	struct gdlm_lock *lpn = NULL;
+	int error;
+
+	if (lp->hold_null) {
+		printk(KERN_INFO "lock_dlm: lvb already held\n");
+		return 0;
+	}
+
+	error = gdlm_create_lp(lp->ls, &lp->lockname, &lpn);
+	if (error)
+		goto out;
+
+	lpn->lksb.sb_lvbptr = junk_lvb;
+	lpn->lvb = junk_lvb;
+
+	lpn->req = DLM_LOCK_NL;
+	lpn->lkf = DLM_LKF_VALBLK | DLM_LKF_EXPEDITE;
+	set_bit(LFL_NOBAST, &lpn->flags);
+	set_bit(LFL_INLOCK, &lpn->flags);
+
+	init_completion(&lpn->ast_wait);
+	gdlm_do_lock(lpn);
+	wait_for_completion(&lpn->ast_wait);
+	error = lpn->lksb.sb_status;
+	if (error) {
+		printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n",
+		       error);
+		gdlm_delete_lp(lpn);
+		lpn = NULL;
+	}
+out:
+	lp->hold_null = lpn;
+	return error;
+}
+
+/* This cannot do a synchronous dlm request (requiring a lock_dlm thread to get
+   the completion) because gfs may call unhold_lvb() during a callback (from
+   the context of a lock_dlm thread) which could cause a deadlock since the
+   other lock_dlm thread could be engaged in recovery. */
+
+static void unhold_null_lock(struct gdlm_lock *lp)
+{
+	struct gdlm_lock *lpn = lp->hold_null;
+
+	gdlm_assert(lpn, "%x,%llx", lp->lockname.ln_type,
+		    (unsigned long long)lp->lockname.ln_number);
+	lpn->lksb.sb_lvbptr = NULL;
+	lpn->lvb = NULL;
+	set_bit(LFL_UNLOCK_DELETE, &lpn->flags);
+	gdlm_do_unlock(lpn);
+	lp->hold_null = NULL;
+}
+
+/* Acquire a NL lock because gfs requires the value block to remain
+   intact on the resource while the lvb is "held" even if it's holding no locks
+   on the resource. */
+
+int gdlm_hold_lvb(void *lock, char **lvbp)
+{
+	struct gdlm_lock *lp = lock;
+	int error;
+
+	error = gdlm_add_lvb(lp);
+	if (error)
+		return error;
+
+	*lvbp = lp->lvb;
+
+	error = hold_null_lock(lp);
+	if (error)
+		gdlm_del_lvb(lp);
+
+	return error;
+}
+
+void gdlm_unhold_lvb(void *lock, char *lvb)
+{
+	struct gdlm_lock *lp = lock;
+
+	unhold_null_lock(lp);
+	gdlm_del_lvb(lp);
+}
+
+void gdlm_submit_delayed(struct gdlm_ls *ls)
+{
+	struct gdlm_lock *lp, *safe;
+
+	spin_lock(&ls->async_lock);
+	list_for_each_entry_safe(lp, safe, &ls->delayed, delay_list) {
+		list_del_init(&lp->delay_list);
+		list_add_tail(&lp->delay_list, &ls->submit);
+	}
+	spin_unlock(&ls->async_lock);
+	wake_up(&ls->thread_wait);
+}
+
+int gdlm_release_all_locks(struct gdlm_ls *ls)
+{
+	struct gdlm_lock *lp, *safe;
+	int count = 0;
+
+	spin_lock(&ls->async_lock);
+	list_for_each_entry_safe(lp, safe, &ls->all_locks, all_list) {
+		list_del_init(&lp->all_list);
+
+		if (lp->lvb && lp->lvb != junk_lvb)
+			kfree(lp->lvb);
+		kfree(lp);
+		count++;
+	}
+	spin_unlock(&ls->async_lock);
+
+	return count;
+}
+
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
new file mode 100644
index 0000000..33af707
--- /dev/null
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef LOCK_DLM_DOT_H
+#define LOCK_DLM_DOT_H
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/fcntl.h>
+#include <linux/wait.h>
+#include <net/sock.h>
+
+#include <linux/dlm.h>
+#include <linux/lm_interface.h>
+
+/*
+ * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a
+ * prefix of lock_dlm_ gets awkward.  Externally, GFS refers to this module
+ * as "lock_dlm".
+ */
+
+#define GDLM_STRNAME_BYTES	24
+#define GDLM_LVB_SIZE		32
+#define GDLM_DROP_COUNT		50000
+#define GDLM_DROP_PERIOD	60
+#define GDLM_NAME_LEN		128
+
+/* GFS uses 12 bytes to identify a resource (32 bit type + 64 bit number).
+   We sprintf these numbers into a 24 byte string of hex values to make them
+   human-readable (to make debugging simpler.) */
+
+struct gdlm_strname {
+	unsigned char		name[GDLM_STRNAME_BYTES];
+	unsigned short		namelen;
+};
+
+enum {
+	DFL_BLOCK_LOCKS		= 0,
+	DFL_SPECTATOR		= 1,
+	DFL_WITHDRAW		= 2,
+};
+
+struct gdlm_ls {
+	u32		id;
+	int			jid;
+	int			first;
+	int			first_done;
+	unsigned long		flags;
+	struct kobject		kobj;
+	char			clustername[GDLM_NAME_LEN];
+	char			fsname[GDLM_NAME_LEN];
+	int			fsflags;
+	dlm_lockspace_t		*dlm_lockspace;
+	lm_callback_t		fscb;
+	struct gfs2_sbd		*sdp;
+	int			recover_jid;
+	int			recover_jid_done;
+	int			recover_jid_status;
+	spinlock_t		async_lock;
+	struct list_head	complete;
+	struct list_head	blocking;
+	struct list_head	delayed;
+	struct list_head	submit;
+	struct list_head	all_locks;
+	u32		all_locks_count;
+	wait_queue_head_t	wait_control;
+	struct task_struct	*thread1;
+	struct task_struct	*thread2;
+	wait_queue_head_t	thread_wait;
+	unsigned long		drop_time;
+	int			drop_locks_count;
+	int			drop_locks_period;
+};
+
+enum {
+	LFL_NOBLOCK		= 0,
+	LFL_NOCACHE		= 1,
+	LFL_DLM_UNLOCK		= 2,
+	LFL_DLM_CANCEL		= 3,
+	LFL_SYNC_LVB		= 4,
+	LFL_FORCE_PROMOTE	= 5,
+	LFL_REREQUEST		= 6,
+	LFL_ACTIVE		= 7,
+	LFL_INLOCK		= 8,
+	LFL_CANCEL		= 9,
+	LFL_NOBAST		= 10,
+	LFL_HEADQUE		= 11,
+	LFL_UNLOCK_DELETE	= 12,
+};
+
+struct gdlm_lock {
+	struct gdlm_ls		*ls;
+	struct lm_lockname	lockname;
+	char			*lvb;
+	struct dlm_lksb		lksb;
+
+	s16			cur;
+	s16			req;
+	s16			prev_req;
+	u32			lkf;		/* dlm flags DLM_LKF_ */
+	unsigned long		flags;		/* lock_dlm flags LFL_ */
+
+	int			bast_mode;	/* protected by async_lock */
+	struct completion	ast_wait;
+
+	struct list_head	clist;		/* complete */
+	struct list_head	blist;		/* blocking */
+	struct list_head	delay_list;	/* delayed */
+	struct list_head	all_list;	/* all locks for the fs */
+	struct gdlm_lock	*hold_null;	/* NL lock for hold_lvb */
+};
+
+#define gdlm_assert(assertion, fmt, args...)                                  \
+do {                                                                          \
+	if (unlikely(!(assertion))) {                                         \
+		printk(KERN_EMERG "lock_dlm: fatal assertion failed \"%s\"\n" \
+				  "lock_dlm:  " fmt "\n",                     \
+				  #assertion, ##args);                        \
+		BUG();                                                        \
+	}                                                                     \
+} while (0)
+
+#define log_print(lev, fmt, arg...) printk(lev "lock_dlm: " fmt "\n" , ## arg)
+#define log_info(fmt, arg...)  log_print(KERN_INFO , fmt , ## arg)
+#define log_error(fmt, arg...) log_print(KERN_ERR , fmt , ## arg)
+#ifdef LOCK_DLM_LOG_DEBUG
+#define log_debug(fmt, arg...) log_print(KERN_DEBUG , fmt , ## arg)
+#else
+#define log_debug(fmt, arg...)
+#endif
+
+/* sysfs.c */
+
+int gdlm_sysfs_init(void);
+void gdlm_sysfs_exit(void);
+int gdlm_kobject_setup(struct gdlm_ls *, struct kobject *);
+void gdlm_kobject_release(struct gdlm_ls *);
+
+/* thread.c */
+
+int gdlm_init_threads(struct gdlm_ls *);
+void gdlm_release_threads(struct gdlm_ls *);
+
+/* lock.c */
+
+s16 gdlm_make_lmstate(s16);
+void gdlm_queue_delayed(struct gdlm_lock *);
+void gdlm_submit_delayed(struct gdlm_ls *);
+int gdlm_release_all_locks(struct gdlm_ls *);
+void gdlm_delete_lp(struct gdlm_lock *);
+unsigned int gdlm_do_lock(struct gdlm_lock *);
+
+int gdlm_get_lock(void *, struct lm_lockname *, void **);
+void gdlm_put_lock(void *);
+unsigned int gdlm_lock(void *, unsigned int, unsigned int, unsigned int);
+unsigned int gdlm_unlock(void *, unsigned int);
+void gdlm_cancel(void *);
+int gdlm_hold_lvb(void *, char **);
+void gdlm_unhold_lvb(void *, char *);
+
+/* plock.c */
+
+int gdlm_plock_init(void);
+void gdlm_plock_exit(void);
+int gdlm_plock(void *, struct lm_lockname *, struct file *, int,
+		struct file_lock *);
+int gdlm_plock_get(void *, struct lm_lockname *, struct file *,
+		struct file_lock *);
+int gdlm_punlock(void *, struct lm_lockname *, struct file *,
+		struct file_lock *);
+#endif
+
diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c
new file mode 100644
index 0000000..2194b1d
--- /dev/null
+++ b/fs/gfs2/locking/dlm/main.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/init.h>
+
+#include "lock_dlm.h"
+
+extern int gdlm_drop_count;
+extern int gdlm_drop_period;
+
+extern struct lm_lockops gdlm_ops;
+
+static int __init init_lock_dlm(void)
+{
+	int error;
+
+	error = gfs2_register_lockproto(&gdlm_ops);
+	if (error) {
+		printk(KERN_WARNING "lock_dlm:  can't register protocol: %d\n",
+		       error);
+		return error;
+	}
+
+	error = gdlm_sysfs_init();
+	if (error) {
+		gfs2_unregister_lockproto(&gdlm_ops);
+		return error;
+	}
+
+	error = gdlm_plock_init();
+	if (error) {
+		gdlm_sysfs_exit();
+		gfs2_unregister_lockproto(&gdlm_ops);
+		return error;
+	}
+
+	gdlm_drop_count = GDLM_DROP_COUNT;
+	gdlm_drop_period = GDLM_DROP_PERIOD;
+
+	printk(KERN_INFO
+	       "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__);
+	return 0;
+}
+
+static void __exit exit_lock_dlm(void)
+{
+	gdlm_plock_exit();
+	gdlm_sysfs_exit();
+	gfs2_unregister_lockproto(&gdlm_ops);
+}
+
+module_init(init_lock_dlm);
+module_exit(exit_lock_dlm);
+
+MODULE_DESCRIPTION("GFS DLM Locking Module");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
new file mode 100644
index 0000000..1f94dd3
--- /dev/null
+++ b/fs/gfs2/locking/dlm/mount.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include "lock_dlm.h"
+
+int gdlm_drop_count;
+int gdlm_drop_period;
+const struct lm_lockops gdlm_ops;
+
+
+static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
+				 int flags, char *table_name)
+{
+	struct gdlm_ls *ls;
+	char buf[256], *p;
+
+	ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
+	if (!ls)
+		return NULL;
+
+	ls->drop_locks_count = gdlm_drop_count;
+	ls->drop_locks_period = gdlm_drop_period;
+	ls->fscb = cb;
+	ls->sdp = sdp;
+	ls->fsflags = flags;
+	spin_lock_init(&ls->async_lock);
+	INIT_LIST_HEAD(&ls->complete);
+	INIT_LIST_HEAD(&ls->blocking);
+	INIT_LIST_HEAD(&ls->delayed);
+	INIT_LIST_HEAD(&ls->submit);
+	INIT_LIST_HEAD(&ls->all_locks);
+	init_waitqueue_head(&ls->thread_wait);
+	init_waitqueue_head(&ls->wait_control);
+	ls->thread1 = NULL;
+	ls->thread2 = NULL;
+	ls->drop_time = jiffies;
+	ls->jid = -1;
+
+	strncpy(buf, table_name, 256);
+	buf[255] = '\0';
+
+	p = strstr(buf, ":");
+	if (!p) {
+		log_info("invalid table_name \"%s\"", table_name);
+		kfree(ls);
+		return NULL;
+	}
+	*p = '\0';
+	p++;
+
+	strncpy(ls->clustername, buf, GDLM_NAME_LEN);
+	strncpy(ls->fsname, p, GDLM_NAME_LEN);
+
+	return ls;
+}
+
+static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
+{
+	char data[256];
+	char *options, *x, *y;
+	int error = 0;
+
+	memset(data, 0, 256);
+	strncpy(data, data_arg, 255);
+
+	for (options = data; (x = strsep(&options, ":")); ) {
+		if (!*x)
+			continue;
+
+		y = strchr(x, '=');
+		if (y)
+			*y++ = 0;
+
+		if (!strcmp(x, "jid")) {
+			if (!y) {
+				log_error("need argument to jid");
+				error = -EINVAL;
+				break;
+			}
+			sscanf(y, "%u", &ls->jid);
+
+		} else if (!strcmp(x, "first")) {
+			if (!y) {
+				log_error("need argument to first");
+				error = -EINVAL;
+				break;
+			}
+			sscanf(y, "%u", &ls->first);
+
+		} else if (!strcmp(x, "id")) {
+			if (!y) {
+				log_error("need argument to id");
+				error = -EINVAL;
+				break;
+			}
+			sscanf(y, "%u", &ls->id);
+
+		} else if (!strcmp(x, "nodir")) {
+			if (!y) {
+				log_error("need argument to nodir");
+				error = -EINVAL;
+				break;
+			}
+			sscanf(y, "%u", nodir);
+
+		} else {
+			log_error("unkonwn option: %s", x);
+			error = -EINVAL;
+			break;
+		}
+	}
+
+	return error;
+}
+
+static int gdlm_mount(char *table_name, char *host_data,
+			lm_callback_t cb, void *cb_data,
+			unsigned int min_lvb_size, int flags,
+			struct lm_lockstruct *lockstruct,
+			struct kobject *fskobj)
+{
+	struct gdlm_ls *ls;
+	int error = -ENOMEM, nodir = 0;
+
+	if (min_lvb_size > GDLM_LVB_SIZE)
+		goto out;
+
+	ls = init_gdlm(cb, cb_data, flags, table_name);
+	if (!ls)
+		goto out;
+
+	error = make_args(ls, host_data, &nodir);
+	if (error)
+		goto out;
+
+	error = gdlm_init_threads(ls);
+	if (error)
+		goto out_free;
+
+	error = gdlm_kobject_setup(ls, fskobj);
+	if (error)
+		goto out_thread;
+
+	error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
+				  &ls->dlm_lockspace,
+				  nodir ? DLM_LSFL_NODIR : 0,
+				  GDLM_LVB_SIZE);
+	if (error) {
+		log_error("dlm_new_lockspace error %d", error);
+		goto out_kobj;
+	}
+
+	lockstruct->ls_jid = ls->jid;
+	lockstruct->ls_first = ls->first;
+	lockstruct->ls_lockspace = ls;
+	lockstruct->ls_ops = &gdlm_ops;
+	lockstruct->ls_flags = 0;
+	lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
+	return 0;
+
+out_kobj:
+	gdlm_kobject_release(ls);
+out_thread:
+	gdlm_release_threads(ls);
+out_free:
+	kfree(ls);
+out:
+	return error;
+}
+
+static void gdlm_unmount(void *lockspace)
+{
+	struct gdlm_ls *ls = lockspace;
+	int rv;
+
+	log_debug("unmount flags %lx", ls->flags);
+
+	/* FIXME: serialize unmount and withdraw in case they
+	   happen at once.  Also, if unmount follows withdraw,
+	   wait for withdraw to finish. */
+
+	if (test_bit(DFL_WITHDRAW, &ls->flags))
+		goto out;
+
+	gdlm_kobject_release(ls);
+	dlm_release_lockspace(ls->dlm_lockspace, 2);
+	gdlm_release_threads(ls);
+	rv = gdlm_release_all_locks(ls);
+	if (rv)
+		log_info("gdlm_unmount: %d stray locks freed", rv);
+out:
+	kfree(ls);
+}
+
+static void gdlm_recovery_done(void *lockspace, unsigned int jid,
+                               unsigned int message)
+{
+	struct gdlm_ls *ls = lockspace;
+	ls->recover_jid_done = jid;
+	ls->recover_jid_status = message;
+	kobject_uevent(&ls->kobj, KOBJ_CHANGE);
+}
+
+static void gdlm_others_may_mount(void *lockspace)
+{
+	struct gdlm_ls *ls = lockspace;
+	ls->first_done = 1;
+	kobject_uevent(&ls->kobj, KOBJ_CHANGE);
+}
+
+/* Userspace gets the offline uevent, blocks new gfs locks on
+   other mounters, and lets us know (sets WITHDRAW flag).  Then,
+   userspace leaves the mount group while we leave the lockspace. */
+
+static void gdlm_withdraw(void *lockspace)
+{
+	struct gdlm_ls *ls = lockspace;
+
+	kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
+
+	wait_event_interruptible(ls->wait_control,
+				 test_bit(DFL_WITHDRAW, &ls->flags));
+
+	dlm_release_lockspace(ls->dlm_lockspace, 2);
+	gdlm_release_threads(ls);
+	gdlm_release_all_locks(ls);
+	gdlm_kobject_release(ls);
+}
+
+const struct lm_lockops gdlm_ops = {
+	.lm_proto_name = "lock_dlm",
+	.lm_mount = gdlm_mount,
+	.lm_others_may_mount = gdlm_others_may_mount,
+	.lm_unmount = gdlm_unmount,
+	.lm_withdraw = gdlm_withdraw,
+	.lm_get_lock = gdlm_get_lock,
+	.lm_put_lock = gdlm_put_lock,
+	.lm_lock = gdlm_lock,
+	.lm_unlock = gdlm_unlock,
+	.lm_plock = gdlm_plock,
+	.lm_punlock = gdlm_punlock,
+	.lm_plock_get = gdlm_plock_get,
+	.lm_cancel = gdlm_cancel,
+	.lm_hold_lvb = gdlm_hold_lvb,
+	.lm_unhold_lvb = gdlm_unhold_lvb,
+	.lm_recovery_done = gdlm_recovery_done,
+	.lm_owner = THIS_MODULE,
+};
+
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
new file mode 100644
index 0000000..7365aec
--- /dev/null
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/lock_dlm_plock.h>
+
+#include "lock_dlm.h"
+
+
+static spinlock_t ops_lock;
+static struct list_head send_list;
+static struct list_head recv_list;
+static wait_queue_head_t send_wq;
+static wait_queue_head_t recv_wq;
+
+struct plock_op {
+	struct list_head list;
+	int done;
+	struct gdlm_plock_info info;
+};
+
+static inline void set_version(struct gdlm_plock_info *info)
+{
+	info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
+	info->version[1] = GDLM_PLOCK_VERSION_MINOR;
+	info->version[2] = GDLM_PLOCK_VERSION_PATCH;
+}
+
+static int check_version(struct gdlm_plock_info *info)
+{
+	if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
+	    (GDLM_PLOCK_VERSION_MINOR < info->version[1])) {
+		log_error("plock device version mismatch: "
+			  "kernel (%u.%u.%u), user (%u.%u.%u)",
+			  GDLM_PLOCK_VERSION_MAJOR,
+			  GDLM_PLOCK_VERSION_MINOR,
+			  GDLM_PLOCK_VERSION_PATCH,
+			  info->version[0],
+			  info->version[1],
+			  info->version[2]);
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void send_op(struct plock_op *op)
+{
+	set_version(&op->info);
+	INIT_LIST_HEAD(&op->list);
+	spin_lock(&ops_lock);
+	list_add_tail(&op->list, &send_list);
+	spin_unlock(&ops_lock);
+	wake_up(&send_wq);
+}
+
+int gdlm_plock(void *lockspace, struct lm_lockname *name,
+	       struct file *file, int cmd, struct file_lock *fl)
+{
+	struct gdlm_ls *ls = lockspace;
+	struct plock_op *op;
+	int rv;
+
+	op = kzalloc(sizeof(*op), GFP_KERNEL);
+	if (!op)
+		return -ENOMEM;
+
+	op->info.optype		= GDLM_PLOCK_OP_LOCK;
+	op->info.pid		= fl->fl_pid;
+	op->info.ex		= (fl->fl_type == F_WRLCK);
+	op->info.wait		= IS_SETLKW(cmd);
+	op->info.fsid		= ls->id;
+	op->info.number		= name->ln_number;
+	op->info.start		= fl->fl_start;
+	op->info.end		= fl->fl_end;
+	op->info.owner		= (__u64)(long) fl->fl_owner;
+
+	send_op(op);
+	wait_event(recv_wq, (op->done != 0));
+
+	spin_lock(&ops_lock);
+	if (!list_empty(&op->list)) {
+		printk(KERN_INFO "plock op on list\n");
+		list_del(&op->list);
+	}
+	spin_unlock(&ops_lock);
+
+	rv = op->info.rv;
+
+	if (!rv) {
+		if (posix_lock_file_wait(file, fl) < 0)
+			log_error("gdlm_plock: vfs lock error %x,%llx",
+				  name->ln_type,
+				  (unsigned long long)name->ln_number);
+	}
+
+	kfree(op);
+	return rv;
+}
+
+int gdlm_punlock(void *lockspace, struct lm_lockname *name,
+		 struct file *file, struct file_lock *fl)
+{
+	struct gdlm_ls *ls = lockspace;
+	struct plock_op *op;
+	int rv;
+
+	op = kzalloc(sizeof(*op), GFP_KERNEL);
+	if (!op)
+		return -ENOMEM;
+
+	if (posix_lock_file_wait(file, fl) < 0)
+		log_error("gdlm_punlock: vfs unlock error %x,%llx",
+			  name->ln_type, (unsigned long long)name->ln_number);
+
+	op->info.optype		= GDLM_PLOCK_OP_UNLOCK;
+	op->info.pid		= fl->fl_pid;
+	op->info.fsid		= ls->id;
+	op->info.number		= name->ln_number;
+	op->info.start		= fl->fl_start;
+	op->info.end		= fl->fl_end;
+	op->info.owner		= (__u64)(long) fl->fl_owner;
+
+	send_op(op);
+	wait_event(recv_wq, (op->done != 0));
+
+	spin_lock(&ops_lock);
+	if (!list_empty(&op->list)) {
+		printk(KERN_INFO "punlock op on list\n");
+		list_del(&op->list);
+	}
+	spin_unlock(&ops_lock);
+
+	rv = op->info.rv;
+
+	kfree(op);
+	return rv;
+}
+
+int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
+		   struct file *file, struct file_lock *fl)
+{
+	struct gdlm_ls *ls = lockspace;
+	struct plock_op *op;
+	int rv;
+
+	op = kzalloc(sizeof(*op), GFP_KERNEL);
+	if (!op)
+		return -ENOMEM;
+
+	op->info.optype		= GDLM_PLOCK_OP_GET;
+	op->info.pid		= fl->fl_pid;
+	op->info.ex		= (fl->fl_type == F_WRLCK);
+	op->info.fsid		= ls->id;
+	op->info.number		= name->ln_number;
+	op->info.start		= fl->fl_start;
+	op->info.end		= fl->fl_end;
+
+	send_op(op);
+	wait_event(recv_wq, (op->done != 0));
+
+	spin_lock(&ops_lock);
+	if (!list_empty(&op->list)) {
+		printk(KERN_INFO "plock_get op on list\n");
+		list_del(&op->list);
+	}
+	spin_unlock(&ops_lock);
+
+	rv = op->info.rv;
+
+	if (rv == 0)
+		fl->fl_type = F_UNLCK;
+	else if (rv > 0) {
+		fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
+		fl->fl_pid = op->info.pid;
+		fl->fl_start = op->info.start;
+		fl->fl_end = op->info.end;
+	}
+
+	kfree(op);
+	return rv;
+}
+
+/* a read copies out one plock request from the send list */
+static ssize_t dev_read(struct file *file, char __user *u, size_t count,
+			loff_t *ppos)
+{
+	struct gdlm_plock_info info;
+	struct plock_op *op = NULL;
+
+	if (count < sizeof(info))
+		return -EINVAL;
+
+	spin_lock(&ops_lock);
+	if (!list_empty(&send_list)) {
+		op = list_entry(send_list.next, struct plock_op, list);
+		list_move(&op->list, &recv_list);
+		memcpy(&info, &op->info, sizeof(info));
+	}
+	spin_unlock(&ops_lock);
+
+	if (!op)
+		return -EAGAIN;
+
+	if (copy_to_user(u, &info, sizeof(info)))
+		return -EFAULT;
+	return sizeof(info);
+}
+
+/* a write copies in one plock result that should match a plock_op
+   on the recv list */
+static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
+			 loff_t *ppos)
+{
+	struct gdlm_plock_info info;
+	struct plock_op *op;
+	int found = 0;
+
+	if (count != sizeof(info))
+		return -EINVAL;
+
+	if (copy_from_user(&info, u, sizeof(info)))
+		return -EFAULT;
+
+	if (check_version(&info))
+		return -EINVAL;
+
+	spin_lock(&ops_lock);
+	list_for_each_entry(op, &recv_list, list) {
+		if (op->info.fsid == info.fsid && op->info.number == info.number &&
+		    op->info.owner == info.owner) {
+			list_del_init(&op->list);
+			found = 1;
+			op->done = 1;
+			memcpy(&op->info, &info, sizeof(info));
+			break;
+		}
+	}
+	spin_unlock(&ops_lock);
+
+	if (found)
+		wake_up(&recv_wq);
+	else
+		printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
+			(unsigned long long)info.number);
+	return count;
+}
+
+static unsigned int dev_poll(struct file *file, poll_table *wait)
+{
+	poll_wait(file, &send_wq, wait);
+
+	spin_lock(&ops_lock);
+	if (!list_empty(&send_list)) {
+		spin_unlock(&ops_lock);
+		return POLLIN | POLLRDNORM;
+	}
+	spin_unlock(&ops_lock);
+	return 0;
+}
+
+static struct file_operations dev_fops = {
+	.read    = dev_read,
+	.write   = dev_write,
+	.poll    = dev_poll,
+	.owner   = THIS_MODULE
+};
+
+static struct miscdevice plock_dev_misc = {
+	.minor = MISC_DYNAMIC_MINOR,
+	.name = GDLM_PLOCK_MISC_NAME,
+	.fops = &dev_fops
+};
+
+int gdlm_plock_init(void)
+{
+	int rv;
+
+	spin_lock_init(&ops_lock);
+	INIT_LIST_HEAD(&send_list);
+	INIT_LIST_HEAD(&recv_list);
+	init_waitqueue_head(&send_wq);
+	init_waitqueue_head(&recv_wq);
+
+	rv = misc_register(&plock_dev_misc);
+	if (rv)
+		printk(KERN_INFO "gdlm_plock_init: misc_register failed %d",
+		       rv);
+	return rv;
+}
+
+void gdlm_plock_exit(void)
+{
+	if (misc_deregister(&plock_dev_misc) < 0)
+		printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed");
+}
+
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
new file mode 100644
index 0000000..29ae06f
--- /dev/null
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/ctype.h>
+#include <linux/stat.h>
+
+#include "lock_dlm.h"
+
+extern struct lm_lockops gdlm_ops;
+
+static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name);
+}
+
+static ssize_t block_show(struct gdlm_ls *ls, char *buf)
+{
+	ssize_t ret;
+	int val = 0;
+
+	if (test_bit(DFL_BLOCK_LOCKS, &ls->flags))
+		val = 1;
+	ret = sprintf(buf, "%d\n", val);
+	return ret;
+}
+
+static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+	ssize_t ret = len;
+	int val;
+
+	val = simple_strtol(buf, NULL, 0);
+
+	if (val == 1)
+		set_bit(DFL_BLOCK_LOCKS, &ls->flags);
+	else if (val == 0) {
+		clear_bit(DFL_BLOCK_LOCKS, &ls->flags);
+		gdlm_submit_delayed(ls);
+	} else {
+		ret = -EINVAL;
+	}
+	return ret;
+}
+
+static ssize_t withdraw_show(struct gdlm_ls *ls, char *buf)
+{
+	ssize_t ret;
+	int val = 0;
+
+	if (test_bit(DFL_WITHDRAW, &ls->flags))
+		val = 1;
+	ret = sprintf(buf, "%d\n", val);
+	return ret;
+}
+
+static ssize_t withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+	ssize_t ret = len;
+	int val;
+
+	val = simple_strtol(buf, NULL, 0);
+
+	if (val == 1)
+		set_bit(DFL_WITHDRAW, &ls->flags);
+	else
+		ret = -EINVAL;
+	wake_up(&ls->wait_control);
+	return ret;
+}
+
+static ssize_t id_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%u\n", ls->id);
+}
+
+static ssize_t jid_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%d\n", ls->jid);
+}
+
+static ssize_t first_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%d\n", ls->first);
+}
+
+static ssize_t first_done_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%d\n", ls->first_done);
+}
+
+static ssize_t recover_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%d\n", ls->recover_jid);
+}
+
+static ssize_t recover_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+	ls->recover_jid = simple_strtol(buf, NULL, 0);
+	ls->fscb(ls->sdp, LM_CB_NEED_RECOVERY, &ls->recover_jid);
+	return len;
+}
+
+static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%d\n", ls->recover_jid_done);
+}
+
+static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf)
+{
+	return sprintf(buf, "%d\n", ls->recover_jid_status);
+}
+
+struct gdlm_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct gdlm_ls *, char *);
+	ssize_t (*store)(struct gdlm_ls *, const char *, size_t);
+};
+
+#define GDLM_ATTR(_name,_mode,_show,_store) \
+static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+GDLM_ATTR(proto_name,     0444, proto_name_show,     NULL);
+GDLM_ATTR(block,          0644, block_show,          block_store);
+GDLM_ATTR(withdraw,       0644, withdraw_show,       withdraw_store);
+GDLM_ATTR(id,             0444, id_show,             NULL);
+GDLM_ATTR(jid,            0444, jid_show,            NULL);
+GDLM_ATTR(first,          0444, first_show,          NULL);
+GDLM_ATTR(first_done,     0444, first_done_show,     NULL);
+GDLM_ATTR(recover,        0644, recover_show,        recover_store);
+GDLM_ATTR(recover_done,   0444, recover_done_show,   NULL);
+GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
+
+static struct attribute *gdlm_attrs[] = {
+	&gdlm_attr_proto_name.attr,
+	&gdlm_attr_block.attr,
+	&gdlm_attr_withdraw.attr,
+	&gdlm_attr_id.attr,
+	&gdlm_attr_jid.attr,
+	&gdlm_attr_first.attr,
+	&gdlm_attr_first_done.attr,
+	&gdlm_attr_recover.attr,
+	&gdlm_attr_recover_done.attr,
+	&gdlm_attr_recover_status.attr,
+	NULL,
+};
+
+static ssize_t gdlm_attr_show(struct kobject *kobj, struct attribute *attr,
+			      char *buf)
+{
+	struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
+	struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
+	return a->show ? a->show(ls, buf) : 0;
+}
+
+static ssize_t gdlm_attr_store(struct kobject *kobj, struct attribute *attr,
+			       const char *buf, size_t len)
+{
+	struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
+	struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
+	return a->store ? a->store(ls, buf, len) : len;
+}
+
+static struct sysfs_ops gdlm_attr_ops = {
+	.show  = gdlm_attr_show,
+	.store = gdlm_attr_store,
+};
+
+static struct kobj_type gdlm_ktype = {
+	.default_attrs = gdlm_attrs,
+	.sysfs_ops     = &gdlm_attr_ops,
+};
+
+static struct kset gdlm_kset = {
+	.subsys = &kernel_subsys,
+	.kobj   = {.name = "lock_dlm",},
+	.ktype  = &gdlm_ktype,
+};
+
+int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj)
+{
+	int error;
+
+	error = kobject_set_name(&ls->kobj, "%s", "lock_module");
+	if (error) {
+		log_error("can't set kobj name %d", error);
+		return error;
+	}
+
+	ls->kobj.kset = &gdlm_kset;
+	ls->kobj.ktype = &gdlm_ktype;
+	ls->kobj.parent = fskobj;
+
+	error = kobject_register(&ls->kobj);
+	if (error)
+		log_error("can't register kobj %d", error);
+
+	return error;
+}
+
+void gdlm_kobject_release(struct gdlm_ls *ls)
+{
+	kobject_unregister(&ls->kobj);
+}
+
+int gdlm_sysfs_init(void)
+{
+	int error;
+
+	error = kset_register(&gdlm_kset);
+	if (error)
+		printk("lock_dlm: cannot register kset %d\n", error);
+
+	return error;
+}
+
+void gdlm_sysfs_exit(void)
+{
+	kset_unregister(&gdlm_kset);
+}
+
diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
new file mode 100644
index 0000000..9cf1f16
--- /dev/null
+++ b/fs/gfs2/locking/dlm/thread.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include "lock_dlm.h"
+
+/* A lock placed on this queue is re-submitted to DLM as soon as the lock_dlm
+   thread gets to it. */
+
+static void queue_submit(struct gdlm_lock *lp)
+{
+	struct gdlm_ls *ls = lp->ls;
+
+	spin_lock(&ls->async_lock);
+	list_add_tail(&lp->delay_list, &ls->submit);
+	spin_unlock(&ls->async_lock);
+	wake_up(&ls->thread_wait);
+}
+
+static void process_blocking(struct gdlm_lock *lp, int bast_mode)
+{
+	struct gdlm_ls *ls = lp->ls;
+	unsigned int cb = 0;
+
+	switch (gdlm_make_lmstate(bast_mode)) {
+	case LM_ST_EXCLUSIVE:
+		cb = LM_CB_NEED_E;
+		break;
+	case LM_ST_DEFERRED:
+		cb = LM_CB_NEED_D;
+		break;
+	case LM_ST_SHARED:
+		cb = LM_CB_NEED_S;
+		break;
+	default:
+		gdlm_assert(0, "unknown bast mode %u", lp->bast_mode);
+	}
+
+	ls->fscb(ls->sdp, cb, &lp->lockname);
+}
+
+static void process_complete(struct gdlm_lock *lp)
+{
+	struct gdlm_ls *ls = lp->ls;
+	struct lm_async_cb acb;
+	s16 prev_mode = lp->cur;
+
+	memset(&acb, 0, sizeof(acb));
+
+	if (lp->lksb.sb_status == -DLM_ECANCEL) {
+		log_info("complete dlm cancel %x,%llx flags %lx",
+		 	 lp->lockname.ln_type,
+			 (unsigned long long)lp->lockname.ln_number,
+			 lp->flags);
+
+		lp->req = lp->cur;
+		acb.lc_ret |= LM_OUT_CANCELED;
+		if (lp->cur == DLM_LOCK_IV)
+			lp->lksb.sb_lkid = 0;
+		goto out;
+	}
+
+	if (test_and_clear_bit(LFL_DLM_UNLOCK, &lp->flags)) {
+		if (lp->lksb.sb_status != -DLM_EUNLOCK) {
+			log_info("unlock sb_status %d %x,%llx flags %lx",
+				 lp->lksb.sb_status, lp->lockname.ln_type,
+				 (unsigned long long)lp->lockname.ln_number,
+				 lp->flags);
+			return;
+		}
+
+		lp->cur = DLM_LOCK_IV;
+		lp->req = DLM_LOCK_IV;
+		lp->lksb.sb_lkid = 0;
+
+		if (test_and_clear_bit(LFL_UNLOCK_DELETE, &lp->flags)) {
+			gdlm_delete_lp(lp);
+			return;
+		}
+		goto out;
+	}
+
+	if (lp->lksb.sb_flags & DLM_SBF_VALNOTVALID)
+		memset(lp->lksb.sb_lvbptr, 0, GDLM_LVB_SIZE);
+
+	if (lp->lksb.sb_flags & DLM_SBF_ALTMODE) {
+		if (lp->req == DLM_LOCK_PR)
+			lp->req = DLM_LOCK_CW;
+		else if (lp->req == DLM_LOCK_CW)
+			lp->req = DLM_LOCK_PR;
+	}
+
+	/*
+	 * A canceled lock request.  The lock was just taken off the delayed
+	 * list and was never even submitted to dlm.
+	 */
+
+	if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) {
+		log_info("complete internal cancel %x,%llx",
+		 	 lp->lockname.ln_type,
+			 (unsigned long long)lp->lockname.ln_number);
+		lp->req = lp->cur;
+		acb.lc_ret |= LM_OUT_CANCELED;
+		goto out;
+	}
+
+	/*
+	 * An error occured.
+	 */
+
+	if (lp->lksb.sb_status) {
+		/* a "normal" error */
+		if ((lp->lksb.sb_status == -EAGAIN) &&
+		    (lp->lkf & DLM_LKF_NOQUEUE)) {
+			lp->req = lp->cur;
+			if (lp->cur == DLM_LOCK_IV)
+				lp->lksb.sb_lkid = 0;
+			goto out;
+		}
+
+		/* this could only happen with cancels I think */
+		log_info("ast sb_status %d %x,%llx flags %lx",
+			 lp->lksb.sb_status, lp->lockname.ln_type,
+			 (unsigned long long)lp->lockname.ln_number,
+			 lp->flags);
+		return;
+	}
+
+	/*
+	 * This is an AST for an EX->EX conversion for sync_lvb from GFS.
+	 */
+
+	if (test_and_clear_bit(LFL_SYNC_LVB, &lp->flags)) {
+		complete(&lp->ast_wait);
+		return;
+	}
+
+	/*
+	 * A lock has been demoted to NL because it initially completed during
+	 * BLOCK_LOCKS.  Now it must be requested in the originally requested
+	 * mode.
+	 */
+
+	if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) {
+		gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx",
+			    lp->lockname.ln_type,
+			    (unsigned long long)lp->lockname.ln_number);
+		gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx",
+			    lp->lockname.ln_type,
+			    (unsigned long long)lp->lockname.ln_number);
+
+		lp->cur = DLM_LOCK_NL;
+		lp->req = lp->prev_req;
+		lp->prev_req = DLM_LOCK_IV;
+		lp->lkf &= ~DLM_LKF_CONVDEADLK;
+
+		set_bit(LFL_NOCACHE, &lp->flags);
+
+		if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
+		    !test_bit(LFL_NOBLOCK, &lp->flags))
+			gdlm_queue_delayed(lp);
+		else
+			queue_submit(lp);
+		return;
+	}
+
+	/*
+	 * A request is granted during dlm recovery.  It may be granted
+	 * because the locks of a failed node were cleared.  In that case,
+	 * there may be inconsistent data beneath this lock and we must wait
+	 * for recovery to complete to use it.  When gfs recovery is done this
+	 * granted lock will be converted to NL and then reacquired in this
+	 * granted state.
+	 */
+
+	if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
+	    !test_bit(LFL_NOBLOCK, &lp->flags) &&
+	    lp->req != DLM_LOCK_NL) {
+
+		lp->cur = lp->req;
+		lp->prev_req = lp->req;
+		lp->req = DLM_LOCK_NL;
+		lp->lkf |= DLM_LKF_CONVERT;
+		lp->lkf &= ~DLM_LKF_CONVDEADLK;
+
+		log_debug("rereq %x,%llx id %x %d,%d",
+			  lp->lockname.ln_type,
+			  (unsigned long long)lp->lockname.ln_number,
+			  lp->lksb.sb_lkid, lp->cur, lp->req);
+
+		set_bit(LFL_REREQUEST, &lp->flags);
+		queue_submit(lp);
+		return;
+	}
+
+	/*
+	 * DLM demoted the lock to NL before it was granted so GFS must be
+	 * told it cannot cache data for this lock.
+	 */
+
+	if (lp->lksb.sb_flags & DLM_SBF_DEMOTED)
+		set_bit(LFL_NOCACHE, &lp->flags);
+
+out:
+	/*
+	 * This is an internal lock_dlm lock
+	 */
+
+	if (test_bit(LFL_INLOCK, &lp->flags)) {
+		clear_bit(LFL_NOBLOCK, &lp->flags);
+		lp->cur = lp->req;
+		complete(&lp->ast_wait);
+		return;
+	}
+
+	/*
+	 * Normal completion of a lock request.  Tell GFS it now has the lock.
+	 */
+
+	clear_bit(LFL_NOBLOCK, &lp->flags);
+	lp->cur = lp->req;
+
+	acb.lc_name = lp->lockname;
+	acb.lc_ret |= gdlm_make_lmstate(lp->cur);
+
+	if (!test_and_clear_bit(LFL_NOCACHE, &lp->flags) &&
+	    (lp->cur > DLM_LOCK_NL) && (prev_mode > DLM_LOCK_NL))
+		acb.lc_ret |= LM_OUT_CACHEABLE;
+
+	ls->fscb(ls->sdp, LM_CB_ASYNC, &acb);
+}
+
+static inline int no_work(struct gdlm_ls *ls, int blocking)
+{
+	int ret;
+
+	spin_lock(&ls->async_lock);
+	ret = list_empty(&ls->complete) && list_empty(&ls->submit);
+	if (ret && blocking)
+		ret = list_empty(&ls->blocking);
+	spin_unlock(&ls->async_lock);
+
+	return ret;
+}
+
+static inline int check_drop(struct gdlm_ls *ls)
+{
+	if (!ls->drop_locks_count)
+		return 0;
+
+	if (time_after(jiffies, ls->drop_time + ls->drop_locks_period * HZ)) {
+		ls->drop_time = jiffies;
+		if (ls->all_locks_count >= ls->drop_locks_count)
+			return 1;
+	}
+	return 0;
+}
+
+static int gdlm_thread(void *data)
+{
+	struct gdlm_ls *ls = (struct gdlm_ls *) data;
+	struct gdlm_lock *lp = NULL;
+	int blist = 0;
+	uint8_t complete, blocking, submit, drop;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/* Only thread1 is allowed to do blocking callbacks since gfs
+	   may wait for a completion callback within a blocking cb. */
+
+	if (current == ls->thread1)
+		blist = 1;
+
+	while (!kthread_should_stop()) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&ls->thread_wait, &wait);
+		if (no_work(ls, blist))
+			schedule();
+		remove_wait_queue(&ls->thread_wait, &wait);
+		set_current_state(TASK_RUNNING);
+
+		complete = blocking = submit = drop = 0;
+
+		spin_lock(&ls->async_lock);
+
+		if (blist && !list_empty(&ls->blocking)) {
+			lp = list_entry(ls->blocking.next, struct gdlm_lock,
+					blist);
+			list_del_init(&lp->blist);
+			blocking = lp->bast_mode;
+			lp->bast_mode = 0;
+		} else if (!list_empty(&ls->complete)) {
+			lp = list_entry(ls->complete.next, struct gdlm_lock,
+					clist);
+			list_del_init(&lp->clist);
+			complete = 1;
+		} else if (!list_empty(&ls->submit)) {
+			lp = list_entry(ls->submit.next, struct gdlm_lock,
+					delay_list);
+			list_del_init(&lp->delay_list);
+			submit = 1;
+		}
+
+		drop = check_drop(ls);
+		spin_unlock(&ls->async_lock);
+
+		if (complete)
+			process_complete(lp);
+
+		else if (blocking)
+			process_blocking(lp, blocking);
+
+		else if (submit)
+			gdlm_do_lock(lp);
+
+		if (drop)
+			ls->fscb(ls->sdp, LM_CB_DROPLOCKS, NULL);
+
+		schedule();
+	}
+
+	return 0;
+}
+
+int gdlm_init_threads(struct gdlm_ls *ls)
+{
+	struct task_struct *p;
+	int error;
+
+	p = kthread_run(gdlm_thread, ls, "lock_dlm1");
+	error = IS_ERR(p);
+	if (error) {
+		log_error("can't start lock_dlm1 thread %d", error);
+		return error;
+	}
+	ls->thread1 = p;
+
+	p = kthread_run(gdlm_thread, ls, "lock_dlm2");
+	error = IS_ERR(p);
+	if (error) {
+		log_error("can't start lock_dlm2 thread %d", error);
+		kthread_stop(ls->thread1);
+		return error;
+	}
+	ls->thread2 = p;
+
+	return 0;
+}
+
+void gdlm_release_threads(struct gdlm_ls *ls)
+{
+	kthread_stop(ls->thread1);
+	kthread_stop(ls->thread2);
+}
+
diff --git a/fs/gfs2/locking/nolock/Makefile b/fs/gfs2/locking/nolock/Makefile
new file mode 100644
index 0000000..35e9730
--- /dev/null
+++ b/fs/gfs2/locking/nolock/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += lock_nolock.o
+lock_nolock-y := main.o
+
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
new file mode 100644
index 0000000..acfbc94
--- /dev/null
+++ b/fs/gfs2/locking/nolock/main.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/lm_interface.h>
+
+struct nolock_lockspace {
+	unsigned int nl_lvb_size;
+};
+
+static const struct lm_lockops nolock_ops;
+
+static int nolock_mount(char *table_name, char *host_data,
+			lm_callback_t cb, void *cb_data,
+			unsigned int min_lvb_size, int flags,
+			struct lm_lockstruct *lockstruct,
+			struct kobject *fskobj)
+{
+	char *c;
+	unsigned int jid;
+	struct nolock_lockspace *nl;
+
+	c = strstr(host_data, "jid=");
+	if (!c)
+		jid = 0;
+	else {
+		c += 4;
+		sscanf(c, "%u", &jid);
+	}
+
+	nl = kzalloc(sizeof(struct nolock_lockspace), GFP_KERNEL);
+	if (!nl)
+		return -ENOMEM;
+
+	nl->nl_lvb_size = min_lvb_size;
+
+	lockstruct->ls_jid = jid;
+	lockstruct->ls_first = 1;
+	lockstruct->ls_lvb_size = min_lvb_size;
+	lockstruct->ls_lockspace = nl;
+	lockstruct->ls_ops = &nolock_ops;
+	lockstruct->ls_flags = LM_LSFLAG_LOCAL;
+
+	return 0;
+}
+
+static void nolock_others_may_mount(void *lockspace)
+{
+}
+
+static void nolock_unmount(void *lockspace)
+{
+	struct nolock_lockspace *nl = lockspace;
+	kfree(nl);
+}
+
+static void nolock_withdraw(void *lockspace)
+{
+}
+
+/**
+ * nolock_get_lock - get a lm_lock_t given a descripton of the lock
+ * @lockspace: the lockspace the lock lives in
+ * @name: the name of the lock
+ * @lockp: return the lm_lock_t here
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+static int nolock_get_lock(void *lockspace, struct lm_lockname *name,
+			   void **lockp)
+{
+	*lockp = lockspace;
+	return 0;
+}
+
+/**
+ * nolock_put_lock - get rid of a lock structure
+ * @lock: the lock to throw away
+ *
+ */
+
+static void nolock_put_lock(void *lock)
+{
+}
+
+/**
+ * nolock_lock - acquire a lock
+ * @lock: the lock to manipulate
+ * @cur_state: the current state
+ * @req_state: the requested state
+ * @flags: modifier flags
+ *
+ * Returns: A bitmap of LM_OUT_*
+ */
+
+static unsigned int nolock_lock(void *lock, unsigned int cur_state,
+				unsigned int req_state, unsigned int flags)
+{
+	return req_state | LM_OUT_CACHEABLE;
+}
+
+/**
+ * nolock_unlock - unlock a lock
+ * @lock: the lock to manipulate
+ * @cur_state: the current state
+ *
+ * Returns: 0
+ */
+
+static unsigned int nolock_unlock(void *lock, unsigned int cur_state)
+{
+	return 0;
+}
+
+static void nolock_cancel(void *lock)
+{
+}
+
+/**
+ * nolock_hold_lvb - hold on to a lock value block
+ * @lock: the lock the LVB is associated with
+ * @lvbp: return the lm_lvb_t here
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+static int nolock_hold_lvb(void *lock, char **lvbp)
+{
+	struct nolock_lockspace *nl = lock;
+	int error = 0;
+
+	*lvbp = kzalloc(nl->nl_lvb_size, GFP_KERNEL);
+	if (!*lvbp)
+		error = -ENOMEM;
+
+	return error;
+}
+
+/**
+ * nolock_unhold_lvb - release a LVB
+ * @lock: the lock the LVB is associated with
+ * @lvb: the lock value block
+ *
+ */
+
+static void nolock_unhold_lvb(void *lock, char *lvb)
+{
+	kfree(lvb);
+}
+
+static int nolock_plock_get(void *lockspace, struct lm_lockname *name,
+			    struct file *file, struct file_lock *fl)
+{
+	struct file_lock tmp;
+	int ret;
+
+	ret = posix_test_lock(file, fl, &tmp);
+	fl->fl_type = F_UNLCK;
+	if (ret)
+		memcpy(fl, &tmp, sizeof(struct file_lock));
+
+	return 0;
+}
+
+static int nolock_plock(void *lockspace, struct lm_lockname *name,
+			struct file *file, int cmd, struct file_lock *fl)
+{
+	int error;
+	error = posix_lock_file_wait(file, fl);
+	return error;
+}
+
+static int nolock_punlock(void *lockspace, struct lm_lockname *name,
+			  struct file *file, struct file_lock *fl)
+{
+	int error;
+	error = posix_lock_file_wait(file, fl);
+	return error;
+}
+
+static void nolock_recovery_done(void *lockspace, unsigned int jid,
+				 unsigned int message)
+{
+}
+
+static const struct lm_lockops nolock_ops = {
+	.lm_proto_name = "lock_nolock",
+	.lm_mount = nolock_mount,
+	.lm_others_may_mount = nolock_others_may_mount,
+	.lm_unmount = nolock_unmount,
+	.lm_withdraw = nolock_withdraw,
+	.lm_get_lock = nolock_get_lock,
+	.lm_put_lock = nolock_put_lock,
+	.lm_lock = nolock_lock,
+	.lm_unlock = nolock_unlock,
+	.lm_cancel = nolock_cancel,
+	.lm_hold_lvb = nolock_hold_lvb,
+	.lm_unhold_lvb = nolock_unhold_lvb,
+	.lm_plock_get = nolock_plock_get,
+	.lm_plock = nolock_plock,
+	.lm_punlock = nolock_punlock,
+	.lm_recovery_done = nolock_recovery_done,
+	.lm_owner = THIS_MODULE,
+};
+
+static int __init init_nolock(void)
+{
+	int error;
+
+	error = gfs2_register_lockproto(&nolock_ops);
+	if (error) {
+		printk(KERN_WARNING
+		       "lock_nolock: can't register protocol: %d\n", error);
+		return error;
+	}
+
+	printk(KERN_INFO
+	       "Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__);
+	return 0;
+}
+
+static void __exit exit_nolock(void)
+{
+	gfs2_unregister_lockproto(&nolock_ops);
+}
+
+module_init(init_nolock);
+module_exit(exit_nolock);
+
+MODULE_DESCRIPTION("GFS Nolock Locking Module");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
new file mode 100644
index 0000000..554fe5b
--- /dev/null
+++ b/fs/gfs2/log.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "util.h"
+#include "dir.h"
+
+#define PULL 1
+
+/**
+ * gfs2_struct2blk - compute stuff
+ * @sdp: the filesystem
+ * @nstruct: the number of structures
+ * @ssize: the size of the structures
+ *
+ * Compute the number of log descriptor blocks needed to hold a certain number
+ * of structures of a certain size.
+ *
+ * Returns: the number of blocks needed (minimum is always 1)
+ */
+
+unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
+			     unsigned int ssize)
+{
+	unsigned int blks;
+	unsigned int first, second;
+
+	blks = 1;
+	first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize;
+
+	if (nstruct > first) {
+		second = (sdp->sd_sb.sb_bsize -
+			  sizeof(struct gfs2_meta_header)) / ssize;
+		blks += DIV_ROUND_UP(nstruct - first, second);
+	}
+
+	return blks;
+}
+
+/**
+ * gfs2_ail1_start_one - Start I/O on a part of the AIL
+ * @sdp: the filesystem
+ * @tr: the part of the AIL
+ *
+ */
+
+static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+	struct gfs2_bufdata *bd, *s;
+	struct buffer_head *bh;
+	int retry;
+
+	BUG_ON(!spin_is_locked(&sdp->sd_log_lock));
+
+	do {
+		retry = 0;
+
+		list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,
+						 bd_ail_st_list) {
+			bh = bd->bd_bh;
+
+			gfs2_assert(sdp, bd->bd_ail == ai);
+
+			if (!buffer_busy(bh)) {
+				if (!buffer_uptodate(bh)) {
+					gfs2_log_unlock(sdp);
+					gfs2_io_error_bh(sdp, bh);
+					gfs2_log_lock(sdp);
+				}
+				list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
+				continue;
+			}
+
+			if (!buffer_dirty(bh))
+				continue;
+
+			list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+
+			gfs2_log_unlock(sdp);
+			wait_on_buffer(bh);
+			ll_rw_block(WRITE, 1, &bh);
+			gfs2_log_lock(sdp);
+
+			retry = 1;
+			break;
+		}
+	} while (retry);
+}
+
+/**
+ * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced
+ * @sdp: the filesystem
+ * @ai: the AIL entry
+ *
+ */
+
+static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags)
+{
+	struct gfs2_bufdata *bd, *s;
+	struct buffer_head *bh;
+
+	list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,
+					 bd_ail_st_list) {
+		bh = bd->bd_bh;
+
+		gfs2_assert(sdp, bd->bd_ail == ai);
+
+		if (buffer_busy(bh)) {
+			if (flags & DIO_ALL)
+				continue;
+			else
+				break;
+		}
+
+		if (!buffer_uptodate(bh))
+			gfs2_io_error_bh(sdp, bh);
+
+		list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
+	}
+
+	return list_empty(&ai->ai_ail1_list);
+}
+
+void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
+{
+	struct list_head *head = &sdp->sd_ail1_list;
+	u64 sync_gen;
+	struct list_head *first;
+	struct gfs2_ail *first_ai, *ai, *tmp;
+	int done = 0;
+
+	gfs2_log_lock(sdp);
+	if (list_empty(head)) {
+		gfs2_log_unlock(sdp);
+		return;
+	}
+	sync_gen = sdp->sd_ail_sync_gen++;
+
+	first = head->prev;
+	first_ai = list_entry(first, struct gfs2_ail, ai_list);
+	first_ai->ai_sync_gen = sync_gen;
+	gfs2_ail1_start_one(sdp, first_ai); /* This may drop log lock */
+
+	if (flags & DIO_ALL)
+		first = NULL;
+
+	while(!done) {
+		if (first && (head->prev != first ||
+			      gfs2_ail1_empty_one(sdp, first_ai, 0)))
+			break;
+
+		done = 1;
+		list_for_each_entry_safe_reverse(ai, tmp, head, ai_list) {
+			if (ai->ai_sync_gen >= sync_gen)
+				continue;
+			ai->ai_sync_gen = sync_gen;
+			gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */
+			done = 0;
+			break;
+		}
+	}
+
+	gfs2_log_unlock(sdp);
+}
+
+int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
+{
+	struct gfs2_ail *ai, *s;
+	int ret;
+
+	gfs2_log_lock(sdp);
+
+	list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) {
+		if (gfs2_ail1_empty_one(sdp, ai, flags))
+			list_move(&ai->ai_list, &sdp->sd_ail2_list);
+		else if (!(flags & DIO_ALL))
+			break;
+	}
+
+	ret = list_empty(&sdp->sd_ail1_list);
+
+	gfs2_log_unlock(sdp);
+
+	return ret;
+}
+
+
+/**
+ * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced
+ * @sdp: the filesystem
+ * @ai: the AIL entry
+ *
+ */
+
+static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+	struct list_head *head = &ai->ai_ail2_list;
+	struct gfs2_bufdata *bd;
+
+	while (!list_empty(head)) {
+		bd = list_entry(head->prev, struct gfs2_bufdata,
+				bd_ail_st_list);
+		gfs2_assert(sdp, bd->bd_ail == ai);
+		bd->bd_ail = NULL;
+		list_del(&bd->bd_ail_st_list);
+		list_del(&bd->bd_ail_gl_list);
+		atomic_dec(&bd->bd_gl->gl_ail_count);
+		brelse(bd->bd_bh);
+	}
+}
+
+static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
+{
+	struct gfs2_ail *ai, *safe;
+	unsigned int old_tail = sdp->sd_log_tail;
+	int wrap = (new_tail < old_tail);
+	int a, b, rm;
+
+	gfs2_log_lock(sdp);
+
+	list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) {
+		a = (old_tail <= ai->ai_first);
+		b = (ai->ai_first < new_tail);
+		rm = (wrap) ? (a || b) : (a && b);
+		if (!rm)
+			continue;
+
+		gfs2_ail2_empty_one(sdp, ai);
+		list_del(&ai->ai_list);
+		gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list));
+		gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list));
+		kfree(ai);
+	}
+
+	gfs2_log_unlock(sdp);
+}
+
+/**
+ * gfs2_log_reserve - Make a log reservation
+ * @sdp: The GFS2 superblock
+ * @blks: The number of blocks to reserve
+ *
+ * Returns: errno
+ */
+
+int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
+{
+	unsigned int try = 0;
+
+	if (gfs2_assert_warn(sdp, blks) ||
+	    gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
+		return -EINVAL;
+
+	mutex_lock(&sdp->sd_log_reserve_mutex);
+	gfs2_log_lock(sdp);
+	while(sdp->sd_log_blks_free <= blks) {
+		gfs2_log_unlock(sdp);
+		gfs2_ail1_empty(sdp, 0);
+		gfs2_log_flush(sdp, NULL);
+
+		if (try++)
+			gfs2_ail1_start(sdp, 0);
+		gfs2_log_lock(sdp);
+	}
+	sdp->sd_log_blks_free -= blks;
+	gfs2_log_unlock(sdp);
+	mutex_unlock(&sdp->sd_log_reserve_mutex);
+
+	down_read(&sdp->sd_log_flush_lock);
+
+	return 0;
+}
+
+/**
+ * gfs2_log_release - Release a given number of log blocks
+ * @sdp: The GFS2 superblock
+ * @blks: The number of blocks
+ *
+ */
+
+void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
+{
+
+	gfs2_log_lock(sdp);
+	sdp->sd_log_blks_free += blks;
+	gfs2_assert_withdraw(sdp,
+			     sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
+	gfs2_log_unlock(sdp);
+	up_read(&sdp->sd_log_flush_lock);
+}
+
+static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
+{
+	int error;
+	struct buffer_head bh_map;
+
+	error = gfs2_block_map(sdp->sd_jdesc->jd_inode, lbn, 0, &bh_map, 1);
+	if (error || !bh_map.b_blocknr)
+		printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, bh_map.b_blocknr, lbn);
+	gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
+
+	return bh_map.b_blocknr;
+}
+
+/**
+ * log_distance - Compute distance between two journal blocks
+ * @sdp: The GFS2 superblock
+ * @newer: The most recent journal block of the pair
+ * @older: The older journal block of the pair
+ *
+ *   Compute the distance (in the journal direction) between two
+ *   blocks in the journal
+ *
+ * Returns: the distance in blocks
+ */
+
+static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer,
+					unsigned int older)
+{
+	int dist;
+
+	dist = newer - older;
+	if (dist < 0)
+		dist += sdp->sd_jdesc->jd_blocks;
+
+	return dist;
+}
+
+static unsigned int current_tail(struct gfs2_sbd *sdp)
+{
+	struct gfs2_ail *ai;
+	unsigned int tail;
+
+	gfs2_log_lock(sdp);
+
+	if (list_empty(&sdp->sd_ail1_list)) {
+		tail = sdp->sd_log_head;
+	} else {
+		ai = list_entry(sdp->sd_ail1_list.prev, struct gfs2_ail, ai_list);
+		tail = ai->ai_first;
+	}
+
+	gfs2_log_unlock(sdp);
+
+	return tail;
+}
+
+static inline void log_incr_head(struct gfs2_sbd *sdp)
+{
+	if (sdp->sd_log_flush_head == sdp->sd_log_tail)
+		gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head);
+
+	if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
+		sdp->sd_log_flush_head = 0;
+		sdp->sd_log_flush_wrapped = 1;
+	}
+}
+
+/**
+ * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: the buffer_head
+ */
+
+struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
+{
+	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
+	struct gfs2_log_buf *lb;
+	struct buffer_head *bh;
+
+	lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
+	list_add(&lb->lb_list, &sdp->sd_log_flush_list);
+
+	bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno);
+	lock_buffer(bh);
+	memset(bh->b_data, 0, bh->b_size);
+	set_buffer_uptodate(bh);
+	clear_buffer_dirty(bh);
+	unlock_buffer(bh);
+
+	log_incr_head(sdp);
+
+	return bh;
+}
+
+/**
+ * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
+ * @sdp: the filesystem
+ * @data: the data the buffer_head should point to
+ *
+ * Returns: the log buffer descriptor
+ */
+
+struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+				      struct buffer_head *real)
+{
+	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
+	struct gfs2_log_buf *lb;
+	struct buffer_head *bh;
+
+	lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
+	list_add(&lb->lb_list, &sdp->sd_log_flush_list);
+	lb->lb_real = real;
+
+	bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
+	atomic_set(&bh->b_count, 1);
+	bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate);
+	set_bh_page(bh, real->b_page, bh_offset(real));
+	bh->b_blocknr = blkno;
+	bh->b_size = sdp->sd_sb.sb_bsize;
+	bh->b_bdev = sdp->sd_vfs->s_bdev;
+
+	log_incr_head(sdp);
+
+	return bh;
+}
+
+static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull)
+{
+	unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
+
+	ail2_empty(sdp, new_tail);
+
+	gfs2_log_lock(sdp);
+	sdp->sd_log_blks_free += dist - (pull ? 1 : 0);
+	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
+	gfs2_log_unlock(sdp);
+
+	sdp->sd_log_tail = new_tail;
+}
+
+/**
+ * log_write_header - Get and initialize a journal header buffer
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: the initialized log buffer descriptor
+ */
+
+static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
+{
+	u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
+	struct buffer_head *bh;
+	struct gfs2_log_header *lh;
+	unsigned int tail;
+	u32 hash;
+
+	bh = sb_getblk(sdp->sd_vfs, blkno);
+	lock_buffer(bh);
+	memset(bh->b_data, 0, bh->b_size);
+	set_buffer_uptodate(bh);
+	clear_buffer_dirty(bh);
+	unlock_buffer(bh);
+
+	gfs2_ail1_empty(sdp, 0);
+	tail = current_tail(sdp);
+
+	lh = (struct gfs2_log_header *)bh->b_data;
+	memset(lh, 0, sizeof(struct gfs2_log_header));
+	lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+	lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
+	lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
+	lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
+	lh->lh_flags = cpu_to_be32(flags);
+	lh->lh_tail = cpu_to_be32(tail);
+	lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
+	hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
+	lh->lh_hash = cpu_to_be32(hash);
+
+	set_buffer_dirty(bh);
+	if (sync_dirty_buffer(bh))
+		gfs2_io_error_bh(sdp, bh);
+	brelse(bh);
+
+	if (sdp->sd_log_tail != tail)
+		log_pull_tail(sdp, tail, pull);
+	else
+		gfs2_assert_withdraw(sdp, !pull);
+
+	sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
+	log_incr_head(sdp);
+}
+
+static void log_flush_commit(struct gfs2_sbd *sdp)
+{
+	struct list_head *head = &sdp->sd_log_flush_list;
+	struct gfs2_log_buf *lb;
+	struct buffer_head *bh;
+
+	while (!list_empty(head)) {
+		lb = list_entry(head->next, struct gfs2_log_buf, lb_list);
+		list_del(&lb->lb_list);
+		bh = lb->lb_bh;
+
+		wait_on_buffer(bh);
+		if (!buffer_uptodate(bh))
+			gfs2_io_error_bh(sdp, bh);
+		if (lb->lb_real) {
+			while (atomic_read(&bh->b_count) != 1)  /* Grrrr... */
+				schedule();
+			free_buffer_head(bh);
+		} else
+			brelse(bh);
+		kfree(lb);
+	}
+
+	log_write_header(sdp, 0, 0);
+}
+
+/**
+ * gfs2_log_flush - flush incore transaction(s)
+ * @sdp: the filesystem
+ * @gl: The glock structure to flush.  If NULL, flush the whole incore log
+ *
+ */
+
+void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
+{
+	struct gfs2_ail *ai;
+
+	down_write(&sdp->sd_log_flush_lock);
+
+	if (gl) {
+		gfs2_log_lock(sdp);
+		if (list_empty(&gl->gl_le.le_list)) {
+			gfs2_log_unlock(sdp);
+			up_write(&sdp->sd_log_flush_lock);
+			return;
+		}
+		gfs2_log_unlock(sdp);
+	}
+
+	ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
+	INIT_LIST_HEAD(&ai->ai_ail1_list);
+	INIT_LIST_HEAD(&ai->ai_ail2_list);
+
+	gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf == sdp->sd_log_commited_buf);
+	gfs2_assert_withdraw(sdp,
+			sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
+
+	sdp->sd_log_flush_head = sdp->sd_log_head;
+	sdp->sd_log_flush_wrapped = 0;
+	ai->ai_first = sdp->sd_log_flush_head;
+
+	lops_before_commit(sdp);
+	if (!list_empty(&sdp->sd_log_flush_list))
+		log_flush_commit(sdp);
+	else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle)
+		log_write_header(sdp, 0, PULL);
+	lops_after_commit(sdp, ai);
+	sdp->sd_log_head = sdp->sd_log_flush_head;
+
+	sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs;
+
+	sdp->sd_log_blks_reserved = 0;
+	sdp->sd_log_commited_buf = 0;
+	sdp->sd_log_num_hdrs = 0;
+	sdp->sd_log_commited_revoke = 0;
+
+	gfs2_log_lock(sdp);
+	if (!list_empty(&ai->ai_ail1_list)) {
+		list_add(&ai->ai_list, &sdp->sd_ail1_list);
+		ai = NULL;
+	}
+	gfs2_log_unlock(sdp);
+
+	sdp->sd_vfs->s_dirt = 0;
+	up_write(&sdp->sd_log_flush_lock);
+
+	kfree(ai);
+}
+
+static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+{
+	unsigned int reserved = 0;
+	unsigned int old;
+
+	gfs2_log_lock(sdp);
+
+	sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm;
+	gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_buf) >= 0);
+	sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
+	gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
+
+	if (sdp->sd_log_commited_buf)
+		reserved += sdp->sd_log_commited_buf;
+	if (sdp->sd_log_commited_revoke)
+		reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke,
+					    sizeof(u64));
+	if (reserved)
+		reserved++;
+
+	old = sdp->sd_log_blks_free;
+	sdp->sd_log_blks_free += tr->tr_reserved -
+				 (reserved - sdp->sd_log_blks_reserved);
+
+	gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old);
+	gfs2_assert_withdraw(sdp,
+			     sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks +
+			     sdp->sd_log_num_hdrs);
+
+	sdp->sd_log_blks_reserved = reserved;
+
+	gfs2_log_unlock(sdp);
+}
+
+/**
+ * gfs2_log_commit - Commit a transaction to the log
+ * @sdp: the filesystem
+ * @tr: the transaction
+ *
+ * Returns: errno
+ */
+
+void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+{
+	log_refund(sdp, tr);
+	lops_incore_commit(sdp, tr);
+
+	sdp->sd_vfs->s_dirt = 1;
+	up_read(&sdp->sd_log_flush_lock);
+
+	gfs2_log_lock(sdp);
+	if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) {
+		gfs2_log_unlock(sdp);
+		gfs2_log_flush(sdp, NULL);
+	} else {
+		gfs2_log_unlock(sdp);
+	}
+}
+
+/**
+ * gfs2_log_shutdown - write a shutdown header into a journal
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_log_shutdown(struct gfs2_sbd *sdp)
+{
+	down_write(&sdp->sd_log_flush_lock);
+
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_hdrs);
+	gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list));
+
+	sdp->sd_log_flush_head = sdp->sd_log_head;
+	sdp->sd_log_flush_wrapped = 0;
+
+	log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0);
+
+	gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks);
+	gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
+	gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
+
+	sdp->sd_log_head = sdp->sd_log_flush_head;
+	sdp->sd_log_tail = sdp->sd_log_head;
+
+	up_write(&sdp->sd_log_flush_lock);
+}
+
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
new file mode 100644
index 0000000..7f5737d
--- /dev/null
+++ b/fs/gfs2/log.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LOG_DOT_H__
+#define __LOG_DOT_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include "incore.h"
+
+/**
+ * gfs2_log_lock - acquire the right to mess with the log manager
+ * @sdp: the filesystem
+ *
+ */
+
+static inline void gfs2_log_lock(struct gfs2_sbd *sdp)
+{
+	spin_lock(&sdp->sd_log_lock);
+}
+
+/**
+ * gfs2_log_unlock - release the right to mess with the log manager
+ * @sdp: the filesystem
+ *
+ */
+
+static inline void gfs2_log_unlock(struct gfs2_sbd *sdp)
+{
+	spin_unlock(&sdp->sd_log_lock);
+}
+
+static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
+					  unsigned int value)
+{
+	if (++value == sdp->sd_jdesc->jd_blocks) {
+		value = 0;
+	}
+	sdp->sd_log_head = sdp->sd_log_tail = value;
+}
+
+unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
+			    unsigned int ssize);
+
+void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags);
+int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
+
+int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
+void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
+
+struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
+struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+				      struct buffer_head *real);
+void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
+void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
+
+void gfs2_log_shutdown(struct gfs2_sbd *sdp);
+
+#endif /* __LOG_DOT_H__ */
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
new file mode 100644
index 0000000..881e337
--- /dev/null
+++ b/fs/gfs2/lops.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+	struct gfs2_glock *gl;
+	struct gfs2_trans *tr = current->journal_info;
+
+	tr->tr_touched = 1;
+
+	if (!list_empty(&le->le_list))
+		return;
+
+	gl = container_of(le, struct gfs2_glock, gl_le);
+	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
+		return;
+	gfs2_glock_hold(gl);
+	set_bit(GLF_DIRTY, &gl->gl_flags);
+
+	gfs2_log_lock(sdp);
+	sdp->sd_log_num_gl++;
+	list_add(&le->le_list, &sdp->sd_log_le_gl);
+	gfs2_log_unlock(sdp);
+}
+
+static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+	struct list_head *head = &sdp->sd_log_le_gl;
+	struct gfs2_glock *gl;
+
+	while (!list_empty(head)) {
+		gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list);
+		list_del_init(&gl->gl_le.le_list);
+		sdp->sd_log_num_gl--;
+
+		gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl));
+		gfs2_glock_put(gl);
+	}
+	gfs2_assert_warn(sdp, !sdp->sd_log_num_gl);
+}
+
+static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+	struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
+	struct gfs2_trans *tr;
+
+	if (!list_empty(&bd->bd_list_tr))
+		return;
+
+	tr = current->journal_info;
+	tr->tr_touched = 1;
+	tr->tr_num_buf++;
+	list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+
+	if (!list_empty(&le->le_list))
+		return;
+
+	gfs2_trans_add_gl(bd->bd_gl);
+
+	gfs2_meta_check(sdp, bd->bd_bh);
+	gfs2_pin(sdp, bd->bd_bh);
+
+	gfs2_log_lock(sdp);
+	sdp->sd_log_num_buf++;
+	list_add(&le->le_list, &sdp->sd_log_le_buf);
+	gfs2_log_unlock(sdp);
+
+	tr->tr_num_buf_new++;
+}
+
+static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+{
+	struct list_head *head = &tr->tr_list_buf;
+	struct gfs2_bufdata *bd;
+
+	while (!list_empty(head)) {
+		bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
+		list_del_init(&bd->bd_list_tr);
+		tr->tr_num_buf--;
+	}
+	gfs2_assert_warn(sdp, !tr->tr_num_buf);
+}
+
+static void buf_lo_before_commit(struct gfs2_sbd *sdp)
+{
+	struct buffer_head *bh;
+	struct gfs2_log_descriptor *ld;
+	struct gfs2_bufdata *bd1 = NULL, *bd2;
+	unsigned int total = sdp->sd_log_num_buf;
+	unsigned int offset = sizeof(struct gfs2_log_descriptor);
+	unsigned int limit;
+	unsigned int num;
+	unsigned n;
+	__be64 *ptr;
+
+	offset += sizeof(__be64) - 1;
+	offset &= ~(sizeof(__be64) - 1);
+	limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64);
+	/* for 4k blocks, limit = 503 */
+
+	bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list);
+	while(total) {
+		num = total;
+		if (total > limit)
+			num = limit;
+		bh = gfs2_log_get_buf(sdp);
+		sdp->sd_log_num_hdrs++;
+		ld = (struct gfs2_log_descriptor *)bh->b_data;
+		ptr = (__be64 *)(bh->b_data + offset);
+		ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+		ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
+		ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
+		ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA);
+		ld->ld_length = cpu_to_be32(num + 1);
+		ld->ld_data1 = cpu_to_be32(num);
+		ld->ld_data2 = cpu_to_be32(0);
+		memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+
+		n = 0;
+		list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf,
+					     bd_le.le_list) {
+			*ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr);
+			if (++n >= num)
+				break;
+		}
+
+		set_buffer_dirty(bh);
+		ll_rw_block(WRITE, 1, &bh);
+
+		n = 0;
+		list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf,
+					     bd_le.le_list) {
+			bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
+			set_buffer_dirty(bh);
+			ll_rw_block(WRITE, 1, &bh);
+			if (++n >= num)
+				break;
+		}
+
+		total -= num;
+	}
+}
+
+static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+	struct list_head *head = &sdp->sd_log_le_buf;
+	struct gfs2_bufdata *bd;
+
+	while (!list_empty(head)) {
+		bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
+		list_del_init(&bd->bd_le.le_list);
+		sdp->sd_log_num_buf--;
+
+		gfs2_unpin(sdp, bd->bd_bh, ai);
+	}
+	gfs2_assert_warn(sdp, !sdp->sd_log_num_buf);
+}
+
+static void buf_lo_before_scan(struct gfs2_jdesc *jd,
+			       struct gfs2_log_header *head, int pass)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+	if (pass != 0)
+		return;
+
+	sdp->sd_found_blocks = 0;
+	sdp->sd_replayed_blocks = 0;
+}
+
+static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+				struct gfs2_log_descriptor *ld, __be64 *ptr,
+				int pass)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+	struct gfs2_glock *gl = ip->i_gl;
+	unsigned int blks = be32_to_cpu(ld->ld_data1);
+	struct buffer_head *bh_log, *bh_ip;
+	u64 blkno;
+	int error = 0;
+
+	if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA)
+		return 0;
+
+	gfs2_replay_incr_blk(sdp, &start);
+
+	for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
+		blkno = be64_to_cpu(*ptr++);
+
+		sdp->sd_found_blocks++;
+
+		if (gfs2_revoke_check(sdp, blkno, start))
+			continue;
+
+		error = gfs2_replay_read_block(jd, start, &bh_log);
+		if (error)
+			return error;
+
+		bh_ip = gfs2_meta_new(gl, blkno);
+		memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
+
+		if (gfs2_meta_check(sdp, bh_ip))
+			error = -EIO;
+		else
+			mark_buffer_dirty(bh_ip);
+
+		brelse(bh_log);
+		brelse(bh_ip);
+
+		if (error)
+			break;
+
+		sdp->sd_replayed_blocks++;
+	}
+
+	return error;
+}
+
+static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+	if (error) {
+		gfs2_meta_sync(ip->i_gl);
+		return;
+	}
+	if (pass != 1)
+		return;
+
+	gfs2_meta_sync(ip->i_gl);
+
+	fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n",
+	        jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
+}
+
+static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+	struct gfs2_trans *tr;
+
+	tr = current->journal_info;
+	tr->tr_touched = 1;
+	tr->tr_num_revoke++;
+
+	gfs2_log_lock(sdp);
+	sdp->sd_log_num_revoke++;
+	list_add(&le->le_list, &sdp->sd_log_le_revoke);
+	gfs2_log_unlock(sdp);
+}
+
+static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
+{
+	struct gfs2_log_descriptor *ld;
+	struct gfs2_meta_header *mh;
+	struct buffer_head *bh;
+	unsigned int offset;
+	struct list_head *head = &sdp->sd_log_le_revoke;
+	struct gfs2_revoke *rv;
+
+	if (!sdp->sd_log_num_revoke)
+		return;
+
+	bh = gfs2_log_get_buf(sdp);
+	ld = (struct gfs2_log_descriptor *)bh->b_data;
+	ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+	ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
+	ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
+	ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE);
+	ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke,
+						    sizeof(u64)));
+	ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke);
+	ld->ld_data2 = cpu_to_be32(0);
+	memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+	offset = sizeof(struct gfs2_log_descriptor);
+
+	while (!list_empty(head)) {
+		rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list);
+		list_del_init(&rv->rv_le.le_list);
+		sdp->sd_log_num_revoke--;
+
+		if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
+			set_buffer_dirty(bh);
+			ll_rw_block(WRITE, 1, &bh);
+
+			bh = gfs2_log_get_buf(sdp);
+			mh = (struct gfs2_meta_header *)bh->b_data;
+			mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
+			mh->mh_type = cpu_to_be32(GFS2_METATYPE_LB);
+			mh->mh_format = cpu_to_be32(GFS2_FORMAT_LB);
+			offset = sizeof(struct gfs2_meta_header);
+		}
+
+		*(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno);
+		kfree(rv);
+
+		offset += sizeof(u64);
+	}
+	gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
+
+	set_buffer_dirty(bh);
+	ll_rw_block(WRITE, 1, &bh);
+}
+
+static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
+				  struct gfs2_log_header *head, int pass)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+	if (pass != 0)
+		return;
+
+	sdp->sd_found_revokes = 0;
+	sdp->sd_replay_tail = head->lh_tail;
+}
+
+static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+				   struct gfs2_log_descriptor *ld, __be64 *ptr,
+				   int pass)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+	unsigned int blks = be32_to_cpu(ld->ld_length);
+	unsigned int revokes = be32_to_cpu(ld->ld_data1);
+	struct buffer_head *bh;
+	unsigned int offset;
+	u64 blkno;
+	int first = 1;
+	int error;
+
+	if (pass != 0 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_REVOKE)
+		return 0;
+
+	offset = sizeof(struct gfs2_log_descriptor);
+
+	for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
+		error = gfs2_replay_read_block(jd, start, &bh);
+		if (error)
+			return error;
+
+		if (!first)
+			gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LB);
+
+		while (offset + sizeof(u64) <= sdp->sd_sb.sb_bsize) {
+			blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset));
+
+			error = gfs2_revoke_add(sdp, blkno, start);
+			if (error < 0)
+				return error;
+			else if (error)
+				sdp->sd_found_revokes++;
+
+			if (!--revokes)
+				break;
+			offset += sizeof(u64);
+		}
+
+		brelse(bh);
+		offset = sizeof(struct gfs2_meta_header);
+		first = 0;
+	}
+
+	return 0;
+}
+
+static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+	if (error) {
+		gfs2_revoke_clean(sdp);
+		return;
+	}
+	if (pass != 1)
+		return;
+
+	fs_info(sdp, "jid=%u: Found %u revoke tags\n",
+	        jd->jd_jid, sdp->sd_found_revokes);
+
+	gfs2_revoke_clean(sdp);
+}
+
+static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_trans *tr = current->journal_info;
+
+	tr->tr_touched = 1;
+
+	if (!list_empty(&le->le_list))
+		return;
+
+	rgd = container_of(le, struct gfs2_rgrpd, rd_le);
+	gfs2_rgrp_bh_hold(rgd);
+
+	gfs2_log_lock(sdp);
+	sdp->sd_log_num_rg++;
+	list_add(&le->le_list, &sdp->sd_log_le_rg);
+	gfs2_log_unlock(sdp);
+}
+
+static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+	struct list_head *head = &sdp->sd_log_le_rg;
+	struct gfs2_rgrpd *rgd;
+
+	while (!list_empty(head)) {
+		rgd = list_entry(head->next, struct gfs2_rgrpd, rd_le.le_list);
+		list_del_init(&rgd->rd_le.le_list);
+		sdp->sd_log_num_rg--;
+
+		gfs2_rgrp_repolish_clones(rgd);
+		gfs2_rgrp_bh_put(rgd);
+	}
+	gfs2_assert_warn(sdp, !sdp->sd_log_num_rg);
+}
+
+/**
+ * databuf_lo_add - Add a databuf to the transaction.
+ *
+ * This is used in two distinct cases:
+ * i) In ordered write mode
+ *    We put the data buffer on a list so that we can ensure that its
+ *    synced to disk at the right time
+ * ii) In journaled data mode
+ *    We need to journal the data block in the same way as metadata in
+ *    the functions above. The difference is that here we have a tag
+ *    which is two __be64's being the block number (as per meta data)
+ *    and a flag which says whether the data block needs escaping or
+ *    not. This means we need a new log entry for each 251 or so data
+ *    blocks, which isn't an enormous overhead but twice as much as
+ *    for normal metadata blocks.
+ */
+static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+	struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
+	struct gfs2_trans *tr = current->journal_info;
+	struct address_space *mapping = bd->bd_bh->b_page->mapping;
+	struct gfs2_inode *ip = GFS2_I(mapping->host);
+
+	tr->tr_touched = 1;
+	if (list_empty(&bd->bd_list_tr) &&
+	    (ip->i_di.di_flags & GFS2_DIF_JDATA)) {
+		tr->tr_num_buf++;
+		list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+		gfs2_pin(sdp, bd->bd_bh);
+		tr->tr_num_buf_new++;
+	}
+	gfs2_trans_add_gl(bd->bd_gl);
+	gfs2_log_lock(sdp);
+	if (list_empty(&le->le_list)) {
+		if (ip->i_di.di_flags & GFS2_DIF_JDATA)
+			sdp->sd_log_num_jdata++;
+		sdp->sd_log_num_databuf++;
+		list_add(&le->le_list, &sdp->sd_log_le_databuf);
+	}
+	gfs2_log_unlock(sdp);
+}
+
+static int gfs2_check_magic(struct buffer_head *bh)
+{
+	struct page *page = bh->b_page;
+	void *kaddr;
+	__be32 *ptr;
+	int rv = 0;
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	ptr = kaddr + bh_offset(bh);
+	if (*ptr == cpu_to_be32(GFS2_MAGIC))
+		rv = 1;
+	kunmap_atomic(page, KM_USER0);
+
+	return rv;
+}
+
+/**
+ * databuf_lo_before_commit - Scan the data buffers, writing as we go
+ *
+ * Here we scan through the lists of buffers and make the assumption
+ * that any buffer thats been pinned is being journaled, and that
+ * any unpinned buffer is an ordered write data buffer and therefore
+ * will be written back rather than journaled.
+ */
+static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
+{
+	LIST_HEAD(started);
+	struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
+	struct buffer_head *bh = NULL;
+	unsigned int offset = sizeof(struct gfs2_log_descriptor);
+	struct gfs2_log_descriptor *ld;
+	unsigned int limit;
+	unsigned int total_dbuf = sdp->sd_log_num_databuf;
+	unsigned int total_jdata = sdp->sd_log_num_jdata;
+	unsigned int num, n;
+	__be64 *ptr = NULL;
+
+	offset += 2*sizeof(__be64) - 1;
+	offset &= ~(2*sizeof(__be64) - 1);
+	limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64);
+
+	/*
+	 * Start writing ordered buffers, write journaled buffers
+	 * into the log along with a header
+	 */
+	gfs2_log_lock(sdp);
+	bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf,
+				       bd_le.le_list);
+	while(total_dbuf) {
+		num = total_jdata;
+		if (num > limit)
+			num = limit;
+		n = 0;
+		list_for_each_entry_safe_continue(bd1, bdt,
+						  &sdp->sd_log_le_databuf,
+						  bd_le.le_list) {
+			/* An ordered write buffer */
+			if (bd1->bd_bh && !buffer_pinned(bd1->bd_bh)) {
+				list_move(&bd1->bd_le.le_list, &started);
+				if (bd1 == bd2) {
+					bd2 = NULL;
+					bd2 = list_prepare_entry(bd2,
+							&sdp->sd_log_le_databuf,
+							bd_le.le_list);
+				}
+				total_dbuf--;
+				if (bd1->bd_bh) {
+					get_bh(bd1->bd_bh);
+					if (buffer_dirty(bd1->bd_bh)) {
+						gfs2_log_unlock(sdp);
+						wait_on_buffer(bd1->bd_bh);
+						ll_rw_block(WRITE, 1,
+							    &bd1->bd_bh);
+						gfs2_log_lock(sdp);
+					}
+					brelse(bd1->bd_bh);
+					continue;
+				}
+				continue;
+			} else if (bd1->bd_bh) { /* A journaled buffer */
+				int magic;
+				gfs2_log_unlock(sdp);
+				if (!bh) {
+					bh = gfs2_log_get_buf(sdp);
+					sdp->sd_log_num_hdrs++;
+					ld = (struct gfs2_log_descriptor *)
+					     bh->b_data;
+					ptr = (__be64 *)(bh->b_data + offset);
+					ld->ld_header.mh_magic =
+						cpu_to_be32(GFS2_MAGIC);
+					ld->ld_header.mh_type =
+						cpu_to_be32(GFS2_METATYPE_LD);
+					ld->ld_header.mh_format =
+						cpu_to_be32(GFS2_FORMAT_LD);
+					ld->ld_type =
+						cpu_to_be32(GFS2_LOG_DESC_JDATA);
+					ld->ld_length = cpu_to_be32(num + 1);
+					ld->ld_data1 = cpu_to_be32(num);
+					ld->ld_data2 = cpu_to_be32(0);
+					memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+				}
+				magic = gfs2_check_magic(bd1->bd_bh);
+				*ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr);
+				*ptr++ = cpu_to_be64((__u64)magic);
+				clear_buffer_escaped(bd1->bd_bh);
+				if (unlikely(magic != 0))
+					set_buffer_escaped(bd1->bd_bh);
+				gfs2_log_lock(sdp);
+				if (n++ > num)
+					break;
+			} else if (!bd1->bd_bh) {
+				total_dbuf--;
+				sdp->sd_log_num_databuf--;
+				list_del_init(&bd1->bd_le.le_list);
+				if (bd1 == bd2) {
+					bd2 = NULL;
+					bd2 = list_prepare_entry(bd2,
+						&sdp->sd_log_le_databuf,
+						bd_le.le_list);
+                                }
+				kmem_cache_free(gfs2_bufdata_cachep, bd1);
+			}
+		}
+		gfs2_log_unlock(sdp);
+		if (bh) {
+			set_buffer_dirty(bh);
+			ll_rw_block(WRITE, 1, &bh);
+			bh = NULL;
+		}
+		n = 0;
+		gfs2_log_lock(sdp);
+		list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf,
+					     bd_le.le_list) {
+			if (!bd2->bd_bh)
+				continue;
+			/* copy buffer if it needs escaping */
+			gfs2_log_unlock(sdp);
+			if (unlikely(buffer_escaped(bd2->bd_bh))) {
+				void *kaddr;
+				struct page *page = bd2->bd_bh->b_page;
+				bh = gfs2_log_get_buf(sdp);
+				kaddr = kmap_atomic(page, KM_USER0);
+				memcpy(bh->b_data,
+				       kaddr + bh_offset(bd2->bd_bh),
+				       sdp->sd_sb.sb_bsize);
+				kunmap_atomic(page, KM_USER0);
+				*(__be32 *)bh->b_data = 0;
+			} else {
+				bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
+			}
+			set_buffer_dirty(bh);
+			ll_rw_block(WRITE, 1, &bh);
+			gfs2_log_lock(sdp);
+			if (++n >= num)
+				break;
+		}
+		bh = NULL;
+		total_dbuf -= num;
+		total_jdata -= num;
+	}
+	gfs2_log_unlock(sdp);
+
+	/* Wait on all ordered buffers */
+	while (!list_empty(&started)) {
+		gfs2_log_lock(sdp);
+		bd1 = list_entry(started.next, struct gfs2_bufdata,
+				 bd_le.le_list);
+		list_del_init(&bd1->bd_le.le_list);
+		sdp->sd_log_num_databuf--;
+		bh = bd1->bd_bh;
+		if (bh) {
+			bh->b_private = NULL;
+			get_bh(bh);
+			gfs2_log_unlock(sdp);
+			wait_on_buffer(bh);
+			brelse(bh);
+		} else
+			gfs2_log_unlock(sdp);
+
+		kmem_cache_free(gfs2_bufdata_cachep, bd1);
+	}
+
+	/* We've removed all the ordered write bufs here, so only jdata left */
+	gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata);
+}
+
+static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+				    struct gfs2_log_descriptor *ld,
+				    __be64 *ptr, int pass)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+	struct gfs2_glock *gl = ip->i_gl;
+	unsigned int blks = be32_to_cpu(ld->ld_data1);
+	struct buffer_head *bh_log, *bh_ip;
+	u64 blkno;
+	u64 esc;
+	int error = 0;
+
+	if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA)
+		return 0;
+
+	gfs2_replay_incr_blk(sdp, &start);
+	for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
+		blkno = be64_to_cpu(*ptr++);
+		esc = be64_to_cpu(*ptr++);
+
+		sdp->sd_found_blocks++;
+
+		if (gfs2_revoke_check(sdp, blkno, start))
+			continue;
+
+		error = gfs2_replay_read_block(jd, start, &bh_log);
+		if (error)
+			return error;
+
+		bh_ip = gfs2_meta_new(gl, blkno);
+		memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
+
+		/* Unescape */
+		if (esc) {
+			__be32 *eptr = (__be32 *)bh_ip->b_data;
+			*eptr = cpu_to_be32(GFS2_MAGIC);
+		}
+		mark_buffer_dirty(bh_ip);
+
+		brelse(bh_log);
+		brelse(bh_ip);
+		if (error)
+			break;
+
+		sdp->sd_replayed_blocks++;
+	}
+
+	return error;
+}
+
+/* FIXME: sort out accounting for log blocks etc. */
+
+static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+	if (error) {
+		gfs2_meta_sync(ip->i_gl);
+		return;
+	}
+	if (pass != 1)
+		return;
+
+	/* data sync? */
+	gfs2_meta_sync(ip->i_gl);
+
+	fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n",
+		jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
+}
+
+static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+	struct list_head *head = &sdp->sd_log_le_databuf;
+	struct gfs2_bufdata *bd;
+
+	while (!list_empty(head)) {
+		bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
+		list_del_init(&bd->bd_le.le_list);
+		sdp->sd_log_num_databuf--;
+		sdp->sd_log_num_jdata--;
+		gfs2_unpin(sdp, bd->bd_bh, ai);
+	}
+	gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf);
+	gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata);
+}
+
+
+const struct gfs2_log_operations gfs2_glock_lops = {
+	.lo_add = glock_lo_add,
+	.lo_after_commit = glock_lo_after_commit,
+	.lo_name = "glock",
+};
+
+const struct gfs2_log_operations gfs2_buf_lops = {
+	.lo_add = buf_lo_add,
+	.lo_incore_commit = buf_lo_incore_commit,
+	.lo_before_commit = buf_lo_before_commit,
+	.lo_after_commit = buf_lo_after_commit,
+	.lo_before_scan = buf_lo_before_scan,
+	.lo_scan_elements = buf_lo_scan_elements,
+	.lo_after_scan = buf_lo_after_scan,
+	.lo_name = "buf",
+};
+
+const struct gfs2_log_operations gfs2_revoke_lops = {
+	.lo_add = revoke_lo_add,
+	.lo_before_commit = revoke_lo_before_commit,
+	.lo_before_scan = revoke_lo_before_scan,
+	.lo_scan_elements = revoke_lo_scan_elements,
+	.lo_after_scan = revoke_lo_after_scan,
+	.lo_name = "revoke",
+};
+
+const struct gfs2_log_operations gfs2_rg_lops = {
+	.lo_add = rg_lo_add,
+	.lo_after_commit = rg_lo_after_commit,
+	.lo_name = "rg",
+};
+
+const struct gfs2_log_operations gfs2_databuf_lops = {
+	.lo_add = databuf_lo_add,
+	.lo_incore_commit = buf_lo_incore_commit,
+	.lo_before_commit = databuf_lo_before_commit,
+	.lo_after_commit = databuf_lo_after_commit,
+	.lo_scan_elements = databuf_lo_scan_elements,
+	.lo_after_scan = databuf_lo_after_scan,
+	.lo_name = "databuf",
+};
+
+const struct gfs2_log_operations *gfs2_log_ops[] = {
+	&gfs2_glock_lops,
+	&gfs2_buf_lops,
+	&gfs2_revoke_lops,
+	&gfs2_rg_lops,
+	&gfs2_databuf_lops,
+	NULL,
+};
+
diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h
new file mode 100644
index 0000000..5839c05
--- /dev/null
+++ b/fs/gfs2/lops.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LOPS_DOT_H__
+#define __LOPS_DOT_H__
+
+#include <linux/list.h>
+#include "incore.h"
+
+extern const struct gfs2_log_operations gfs2_glock_lops;
+extern const struct gfs2_log_operations gfs2_buf_lops;
+extern const struct gfs2_log_operations gfs2_revoke_lops;
+extern const struct gfs2_log_operations gfs2_rg_lops;
+extern const struct gfs2_log_operations gfs2_databuf_lops;
+
+extern const struct gfs2_log_operations *gfs2_log_ops[];
+
+static inline void lops_init_le(struct gfs2_log_element *le,
+				const struct gfs2_log_operations *lops)
+{
+	INIT_LIST_HEAD(&le->le_list);
+	le->le_ops = lops;
+}
+
+static inline void lops_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+	if (le->le_ops->lo_add)
+		le->le_ops->lo_add(sdp, le);
+}
+
+static inline void lops_incore_commit(struct gfs2_sbd *sdp,
+				      struct gfs2_trans *tr)
+{
+	int x;
+	for (x = 0; gfs2_log_ops[x]; x++)
+		if (gfs2_log_ops[x]->lo_incore_commit)
+			gfs2_log_ops[x]->lo_incore_commit(sdp, tr);
+}
+
+static inline void lops_before_commit(struct gfs2_sbd *sdp)
+{
+	int x;
+	for (x = 0; gfs2_log_ops[x]; x++)
+		if (gfs2_log_ops[x]->lo_before_commit)
+			gfs2_log_ops[x]->lo_before_commit(sdp);
+}
+
+static inline void lops_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+	int x;
+	for (x = 0; gfs2_log_ops[x]; x++)
+		if (gfs2_log_ops[x]->lo_after_commit)
+			gfs2_log_ops[x]->lo_after_commit(sdp, ai);
+}
+
+static inline void lops_before_scan(struct gfs2_jdesc *jd,
+				    struct gfs2_log_header *head,
+				    unsigned int pass)
+{
+	int x;
+	for (x = 0; gfs2_log_ops[x]; x++)
+		if (gfs2_log_ops[x]->lo_before_scan)
+			gfs2_log_ops[x]->lo_before_scan(jd, head, pass);
+}
+
+static inline int lops_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+				     struct gfs2_log_descriptor *ld,
+				     __be64 *ptr,
+				     unsigned int pass)
+{
+	int x, error;
+	for (x = 0; gfs2_log_ops[x]; x++)
+		if (gfs2_log_ops[x]->lo_scan_elements) {
+			error = gfs2_log_ops[x]->lo_scan_elements(jd, start,
+								  ld, ptr, pass);
+			if (error)
+				return error;
+		}
+
+	return 0;
+}
+
+static inline void lops_after_scan(struct gfs2_jdesc *jd, int error,
+				   unsigned int pass)
+{
+	int x;
+	for (x = 0; gfs2_log_ops[x]; x++)
+		if (gfs2_log_ops[x]->lo_before_scan)
+			gfs2_log_ops[x]->lo_after_scan(jd, error, pass);
+}
+
+#endif /* __LOPS_DOT_H__ */
+
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
new file mode 100644
index 0000000..21508a1
--- /dev/null
+++ b/fs/gfs2/main.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/atomic.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "ops_fstype.h"
+#include "sys.h"
+#include "util.h"
+#include "glock.h"
+
+static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct gfs2_inode *ip = foo;
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		inode_init_once(&ip->i_inode);
+		spin_lock_init(&ip->i_spin);
+		init_rwsem(&ip->i_rw_mutex);
+		memset(ip->i_cache, 0, sizeof(ip->i_cache));
+	}
+}
+
+static void gfs2_init_glock_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct gfs2_glock *gl = foo;
+	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+	    SLAB_CTOR_CONSTRUCTOR) {
+		INIT_HLIST_NODE(&gl->gl_list);
+		spin_lock_init(&gl->gl_spin);
+		INIT_LIST_HEAD(&gl->gl_holders);
+		INIT_LIST_HEAD(&gl->gl_waiters1);
+		INIT_LIST_HEAD(&gl->gl_waiters2);
+		INIT_LIST_HEAD(&gl->gl_waiters3);
+		gl->gl_lvb = NULL;
+		atomic_set(&gl->gl_lvb_count, 0);
+		INIT_LIST_HEAD(&gl->gl_reclaim);
+		INIT_LIST_HEAD(&gl->gl_ail_list);
+		atomic_set(&gl->gl_ail_count, 0);
+	}
+}
+
+/**
+ * init_gfs2_fs - Register GFS2 as a filesystem
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+static int __init init_gfs2_fs(void)
+{
+	int error;
+
+	error = gfs2_sys_init();
+	if (error)
+		return error;
+
+	error = gfs2_glock_init();
+	if (error)
+		goto fail;
+
+	error = -ENOMEM;
+	gfs2_glock_cachep = kmem_cache_create("gfs2_glock",
+					      sizeof(struct gfs2_glock),
+					      0, 0,
+					      gfs2_init_glock_once, NULL);
+	if (!gfs2_glock_cachep)
+		goto fail;
+
+	gfs2_inode_cachep = kmem_cache_create("gfs2_inode",
+					      sizeof(struct gfs2_inode),
+					      0, (SLAB_RECLAIM_ACCOUNT|
+					      SLAB_PANIC|SLAB_MEM_SPREAD),
+					      gfs2_init_inode_once, NULL);
+	if (!gfs2_inode_cachep)
+		goto fail;
+
+	gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata",
+						sizeof(struct gfs2_bufdata),
+					        0, 0, NULL, NULL);
+	if (!gfs2_bufdata_cachep)
+		goto fail;
+
+	error = register_filesystem(&gfs2_fs_type);
+	if (error)
+		goto fail;
+
+	error = register_filesystem(&gfs2meta_fs_type);
+	if (error)
+		goto fail_unregister;
+
+	printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
+
+	return 0;
+
+fail_unregister:
+	unregister_filesystem(&gfs2_fs_type);
+fail:
+	if (gfs2_bufdata_cachep)
+		kmem_cache_destroy(gfs2_bufdata_cachep);
+
+	if (gfs2_inode_cachep)
+		kmem_cache_destroy(gfs2_inode_cachep);
+
+	if (gfs2_glock_cachep)
+		kmem_cache_destroy(gfs2_glock_cachep);
+
+	gfs2_sys_uninit();
+	return error;
+}
+
+/**
+ * exit_gfs2_fs - Unregister the file system
+ *
+ */
+
+static void __exit exit_gfs2_fs(void)
+{
+	unregister_filesystem(&gfs2_fs_type);
+	unregister_filesystem(&gfs2meta_fs_type);
+
+	kmem_cache_destroy(gfs2_bufdata_cachep);
+	kmem_cache_destroy(gfs2_inode_cachep);
+	kmem_cache_destroy(gfs2_glock_cachep);
+
+	gfs2_sys_uninit();
+}
+
+MODULE_DESCRIPTION("Global File System");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+module_init(init_gfs2_fs);
+module_exit(exit_gfs2_fs);
+
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
new file mode 100644
index 0000000..3912d6a
--- /dev/null
+++ b/fs/gfs2/meta_io.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/swap.h>
+#include <linux/delay.h>
+#include <linux/bio.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+#include "ops_address.h"
+
+static int aspace_get_block(struct inode *inode, sector_t lblock,
+			    struct buffer_head *bh_result, int create)
+{
+	gfs2_assert_warn(inode->i_sb->s_fs_info, 0);
+	return -EOPNOTSUPP;
+}
+
+static int gfs2_aspace_writepage(struct page *page,
+				 struct writeback_control *wbc)
+{
+	return block_write_full_page(page, aspace_get_block, wbc);
+}
+
+static const struct address_space_operations aspace_aops = {
+	.writepage = gfs2_aspace_writepage,
+	.releasepage = gfs2_releasepage,
+};
+
+/**
+ * gfs2_aspace_get - Create and initialize a struct inode structure
+ * @sdp: the filesystem the aspace is in
+ *
+ * Right now a struct inode is just a struct inode.  Maybe Linux
+ * will supply a more lightweight address space construct (that works)
+ * in the future.
+ *
+ * Make sure pages/buffers in this aspace aren't in high memory.
+ *
+ * Returns: the aspace
+ */
+
+struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp)
+{
+	struct inode *aspace;
+
+	aspace = new_inode(sdp->sd_vfs);
+	if (aspace) {
+		mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS);
+		aspace->i_mapping->a_ops = &aspace_aops;
+		aspace->i_size = ~0ULL;
+		aspace->i_private = NULL;
+		insert_inode_hash(aspace);
+	}
+	return aspace;
+}
+
+void gfs2_aspace_put(struct inode *aspace)
+{
+	remove_inode_hash(aspace);
+	iput(aspace);
+}
+
+/**
+ * gfs2_meta_inval - Invalidate all buffers associated with a glock
+ * @gl: the glock
+ *
+ */
+
+void gfs2_meta_inval(struct gfs2_glock *gl)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	struct inode *aspace = gl->gl_aspace;
+	struct address_space *mapping = gl->gl_aspace->i_mapping;
+
+	gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
+
+	atomic_inc(&aspace->i_writecount);
+	truncate_inode_pages(mapping, 0);
+	atomic_dec(&aspace->i_writecount);
+
+	gfs2_assert_withdraw(sdp, !mapping->nrpages);
+}
+
+/**
+ * gfs2_meta_sync - Sync all buffers associated with a glock
+ * @gl: The glock
+ *
+ */
+
+void gfs2_meta_sync(struct gfs2_glock *gl)
+{
+	struct address_space *mapping = gl->gl_aspace->i_mapping;
+	int error;
+
+	filemap_fdatawrite(mapping);
+	error = filemap_fdatawait(mapping);
+
+	if (error)
+		gfs2_io_error(gl->gl_sbd);
+}
+
+/**
+ * getbuf - Get a buffer with a given address space
+ * @sdp: the filesystem
+ * @aspace: the address space
+ * @blkno: the block number (filesystem scope)
+ * @create: 1 if the buffer should be created
+ *
+ * Returns: the buffer
+ */
+
+static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace,
+				  u64 blkno, int create)
+{
+	struct page *page;
+	struct buffer_head *bh;
+	unsigned int shift;
+	unsigned long index;
+	unsigned int bufnum;
+
+	shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift;
+	index = blkno >> shift;             /* convert block to page */
+	bufnum = blkno - (index << shift);  /* block buf index within page */
+
+	if (create) {
+		for (;;) {
+			page = grab_cache_page(aspace->i_mapping, index);
+			if (page)
+				break;
+			yield();
+		}
+	} else {
+		page = find_lock_page(aspace->i_mapping, index);
+		if (!page)
+			return NULL;
+	}
+
+	if (!page_has_buffers(page))
+		create_empty_buffers(page, sdp->sd_sb.sb_bsize, 0);
+
+	/* Locate header for our buffer within our page */
+	for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page)
+		/* Do nothing */;
+	get_bh(bh);
+
+	if (!buffer_mapped(bh))
+		map_bh(bh, sdp->sd_vfs, blkno);
+
+	unlock_page(page);
+	mark_page_accessed(page);
+	page_cache_release(page);
+
+	return bh;
+}
+
+static void meta_prep_new(struct buffer_head *bh)
+{
+	struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
+
+	lock_buffer(bh);
+	clear_buffer_dirty(bh);
+	set_buffer_uptodate(bh);
+	unlock_buffer(bh);
+
+	mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
+}
+
+/**
+ * gfs2_meta_new - Get a block
+ * @gl: The glock associated with this block
+ * @blkno: The block number
+ *
+ * Returns: The buffer
+ */
+
+struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno)
+{
+	struct buffer_head *bh;
+	bh = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE);
+	meta_prep_new(bh);
+	return bh;
+}
+
+/**
+ * gfs2_meta_read - Read a block from disk
+ * @gl: The glock covering the block
+ * @blkno: The block number
+ * @flags: flags
+ * @bhp: the place where the buffer is returned (NULL on failure)
+ *
+ * Returns: errno
+ */
+
+int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
+		   struct buffer_head **bhp)
+{
+	*bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE);
+	if (!buffer_uptodate(*bhp))
+		ll_rw_block(READ_META, 1, bhp);
+	if (flags & DIO_WAIT) {
+		int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
+		if (error) {
+			brelse(*bhp);
+			return error;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_meta_wait - Reread a block from disk
+ * @sdp: the filesystem
+ * @bh: The block to wait for
+ *
+ * Returns: errno
+ */
+
+int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		return -EIO;
+
+	wait_on_buffer(bh);
+
+	if (!buffer_uptodate(bh)) {
+		struct gfs2_trans *tr = current->journal_info;
+		if (tr && tr->tr_touched)
+			gfs2_io_error_bh(sdp, bh);
+		return -EIO;
+	}
+	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * gfs2_attach_bufdata - attach a struct gfs2_bufdata structure to a buffer
+ * @gl: the glock the buffer belongs to
+ * @bh: The buffer to be attached to
+ * @meta: Flag to indicate whether its metadata or not
+ */
+
+void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
+			 int meta)
+{
+	struct gfs2_bufdata *bd;
+
+	if (meta)
+		lock_page(bh->b_page);
+
+	if (bh->b_private) {
+		if (meta)
+			unlock_page(bh->b_page);
+		return;
+	}
+
+	bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL),
+	memset(bd, 0, sizeof(struct gfs2_bufdata));
+	bd->bd_bh = bh;
+	bd->bd_gl = gl;
+
+	INIT_LIST_HEAD(&bd->bd_list_tr);
+	if (meta)
+		lops_init_le(&bd->bd_le, &gfs2_buf_lops);
+	else
+		lops_init_le(&bd->bd_le, &gfs2_databuf_lops);
+	bh->b_private = bd;
+
+	if (meta)
+		unlock_page(bh->b_page);
+}
+
+/**
+ * gfs2_pin - Pin a buffer in memory
+ * @sdp: the filesystem the buffer belongs to
+ * @bh: The buffer to be pinned
+ *
+ */
+
+void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+	struct gfs2_bufdata *bd = bh->b_private;
+
+	gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
+
+	if (test_set_buffer_pinned(bh))
+		gfs2_assert_withdraw(sdp, 0);
+
+	wait_on_buffer(bh);
+
+	/* If this buffer is in the AIL and it has already been written
+	   to in-place disk block, remove it from the AIL. */
+
+	gfs2_log_lock(sdp);
+	if (bd->bd_ail && !buffer_in_io(bh))
+		list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
+	gfs2_log_unlock(sdp);
+
+	clear_buffer_dirty(bh);
+	wait_on_buffer(bh);
+
+	if (!buffer_uptodate(bh))
+		gfs2_io_error_bh(sdp, bh);
+
+	get_bh(bh);
+}
+
+/**
+ * gfs2_unpin - Unpin a buffer
+ * @sdp: the filesystem the buffer belongs to
+ * @bh: The buffer to unpin
+ * @ai:
+ *
+ */
+
+void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+	        struct gfs2_ail *ai)
+{
+	struct gfs2_bufdata *bd = bh->b_private;
+
+	gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
+
+	if (!buffer_pinned(bh))
+		gfs2_assert_withdraw(sdp, 0);
+
+	mark_buffer_dirty(bh);
+	clear_buffer_pinned(bh);
+
+	gfs2_log_lock(sdp);
+	if (bd->bd_ail) {
+		list_del(&bd->bd_ail_st_list);
+		brelse(bh);
+	} else {
+		struct gfs2_glock *gl = bd->bd_gl;
+		list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
+		atomic_inc(&gl->gl_ail_count);
+	}
+	bd->bd_ail = ai;
+	list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+	gfs2_log_unlock(sdp);
+}
+
+/**
+ * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore
+ * @ip: the inode who owns the buffers
+ * @bstart: the first buffer in the run
+ * @blen: the number of buffers in the run
+ *
+ */
+
+void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct inode *aspace = ip->i_gl->gl_aspace;
+	struct buffer_head *bh;
+
+	while (blen) {
+		bh = getbuf(sdp, aspace, bstart, NO_CREATE);
+		if (bh) {
+			struct gfs2_bufdata *bd = bh->b_private;
+
+			if (test_clear_buffer_pinned(bh)) {
+				struct gfs2_trans *tr = current->journal_info;
+				gfs2_log_lock(sdp);
+				list_del_init(&bd->bd_le.le_list);
+				gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
+				sdp->sd_log_num_buf--;
+				gfs2_log_unlock(sdp);
+				tr->tr_num_buf_rm++;
+				brelse(bh);
+			}
+			if (bd) {
+				gfs2_log_lock(sdp);
+				if (bd->bd_ail) {
+					u64 blkno = bh->b_blocknr;
+					bd->bd_ail = NULL;
+					list_del(&bd->bd_ail_st_list);
+					list_del(&bd->bd_ail_gl_list);
+					atomic_dec(&bd->bd_gl->gl_ail_count);
+					brelse(bh);
+					gfs2_log_unlock(sdp);
+					gfs2_trans_add_revoke(sdp, blkno);
+				} else
+					gfs2_log_unlock(sdp);
+			}
+
+			lock_buffer(bh);
+			clear_buffer_dirty(bh);
+			clear_buffer_uptodate(bh);
+			unlock_buffer(bh);
+
+			brelse(bh);
+		}
+
+		bstart++;
+		blen--;
+	}
+}
+
+/**
+ * gfs2_meta_cache_flush - get rid of any references on buffers for this inode
+ * @ip: The GFS2 inode
+ *
+ * This releases buffers that are in the most-recently-used array of
+ * blocks used for indirect block addressing for this inode.
+ */
+
+void gfs2_meta_cache_flush(struct gfs2_inode *ip)
+{
+	struct buffer_head **bh_slot;
+	unsigned int x;
+
+	spin_lock(&ip->i_spin);
+
+	for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
+		bh_slot = &ip->i_cache[x];
+		if (!*bh_slot)
+			break;
+		brelse(*bh_slot);
+		*bh_slot = NULL;
+	}
+
+	spin_unlock(&ip->i_spin);
+}
+
+/**
+ * gfs2_meta_indirect_buffer - Get a metadata buffer
+ * @ip: The GFS2 inode
+ * @height: The level of this buf in the metadata (indir addr) tree (if any)
+ * @num: The block number (device relative) of the buffer
+ * @new: Non-zero if we may create a new buffer
+ * @bhp: the buffer is returned here
+ *
+ * Try to use the gfs2_inode's MRU metadata tree cache.
+ *
+ * Returns: errno
+ */
+
+int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
+			      int new, struct buffer_head **bhp)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_glock *gl = ip->i_gl;
+	struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height;
+	int in_cache = 0;
+
+	spin_lock(&ip->i_spin);
+	if (*bh_slot && (*bh_slot)->b_blocknr == num) {
+		bh = *bh_slot;
+		get_bh(bh);
+		in_cache = 1;
+	}
+	spin_unlock(&ip->i_spin);
+
+	if (!bh)
+		bh = getbuf(gl->gl_sbd, gl->gl_aspace, num, CREATE);
+
+	if (!bh)
+		return -ENOBUFS;
+
+	if (new) {
+		if (gfs2_assert_warn(sdp, height))
+			goto err;
+		meta_prep_new(bh);
+		gfs2_trans_add_bh(ip->i_gl, bh, 1);
+		gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+		gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
+	} else {
+		u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
+		if (!buffer_uptodate(bh)) {
+			ll_rw_block(READ_META, 1, &bh);
+			if (gfs2_meta_wait(sdp, bh))
+				goto err;
+		}
+		if (gfs2_metatype_check(sdp, bh, mtype))
+			goto err;
+	}
+
+	if (!in_cache) {
+		spin_lock(&ip->i_spin);
+		if (*bh_slot)
+			brelse(*bh_slot);
+		*bh_slot = bh;
+		get_bh(bh);
+		spin_unlock(&ip->i_spin);
+	}
+
+	*bhp = bh;
+	return 0;
+err:
+	brelse(bh);
+	return -EIO;
+}
+
+/**
+ * gfs2_meta_ra - start readahead on an extent of a file
+ * @gl: the glock the blocks belong to
+ * @dblock: the starting disk block
+ * @extlen: the number of blocks in the extent
+ *
+ * returns: the first buffer in the extent
+ */
+
+struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	struct inode *aspace = gl->gl_aspace;
+	struct buffer_head *first_bh, *bh;
+	u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >>
+			  sdp->sd_sb.sb_bsize_shift;
+
+	BUG_ON(!extlen);
+
+	if (max_ra < 1)
+		max_ra = 1;
+	if (extlen > max_ra)
+		extlen = max_ra;
+
+	first_bh = getbuf(sdp, aspace, dblock, CREATE);
+
+	if (buffer_uptodate(first_bh))
+		goto out;
+	if (!buffer_locked(first_bh))
+		ll_rw_block(READ_META, 1, &first_bh);
+
+	dblock++;
+	extlen--;
+
+	while (extlen) {
+		bh = getbuf(sdp, aspace, dblock, CREATE);
+
+		if (!buffer_uptodate(bh) && !buffer_locked(bh))
+			ll_rw_block(READA, 1, &bh);
+		brelse(bh);
+		dblock++;
+		extlen--;
+		if (!buffer_locked(first_bh) && buffer_uptodate(first_bh))
+			goto out;
+	}
+
+	wait_on_buffer(first_bh);
+out:
+	return first_bh;
+}
+
+/**
+ * gfs2_meta_syncfs - sync all the buffers in a filesystem
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_meta_syncfs(struct gfs2_sbd *sdp)
+{
+	gfs2_log_flush(sdp, NULL);
+	for (;;) {
+		gfs2_ail1_start(sdp, DIO_ALL);
+		if (gfs2_ail1_empty(sdp, DIO_ALL))
+			break;
+		msleep(10);
+	}
+}
+
diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
new file mode 100644
index 0000000..3ec939e
--- /dev/null
+++ b/fs/gfs2/meta_io.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __DIO_DOT_H__
+#define __DIO_DOT_H__
+
+#include <linux/buffer_head.h>
+#include <linux/string.h>
+#include "incore.h"
+
+static inline void gfs2_buffer_clear(struct buffer_head *bh)
+{
+	memset(bh->b_data, 0, bh->b_size);
+}
+
+static inline void gfs2_buffer_clear_tail(struct buffer_head *bh, int head)
+{
+	BUG_ON(head > bh->b_size);
+	memset(bh->b_data + head, 0, bh->b_size - head);
+}
+
+static inline void gfs2_buffer_copy_tail(struct buffer_head *to_bh,
+					 int to_head,
+					 struct buffer_head *from_bh,
+					 int from_head)
+{
+	BUG_ON(from_head < to_head);
+	memcpy(to_bh->b_data + to_head, from_bh->b_data + from_head,
+	       from_bh->b_size - from_head);
+	memset(to_bh->b_data + to_bh->b_size + to_head - from_head,
+	       0, from_head - to_head);
+}
+
+struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp);
+void gfs2_aspace_put(struct inode *aspace);
+
+void gfs2_meta_inval(struct gfs2_glock *gl);
+void gfs2_meta_sync(struct gfs2_glock *gl);
+
+struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
+int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno,
+		   int flags, struct buffer_head **bhp);
+int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
+
+void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
+			 int meta);
+void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
+void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+		struct gfs2_ail *ai);
+
+void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
+
+void gfs2_meta_cache_flush(struct gfs2_inode *ip);
+int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
+			      int new, struct buffer_head **bhp);
+
+static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip,
+					 struct buffer_head **bhp)
+{
+	return gfs2_meta_indirect_buffer(ip, 0, ip->i_num.no_addr, 0, bhp);
+}
+
+struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen);
+void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
+
+#define buffer_busy(bh) \
+((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned)))
+#define buffer_in_io(bh) \
+((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock)))
+
+#endif /* __DIO_DOT_H__ */
+
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
new file mode 100644
index 0000000..ef3092e
--- /dev/null
+++ b/fs/gfs2/mount.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "mount.h"
+#include "sys.h"
+#include "util.h"
+
+/**
+ * gfs2_mount_args - Parse mount options
+ * @sdp:
+ * @data:
+ *
+ * Return: errno
+ */
+
+int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
+{
+	struct gfs2_args *args = &sdp->sd_args;
+	char *data = data_arg;
+	char *options, *o, *v;
+	int error = 0;
+
+	if (!remount) {
+		/*  If someone preloaded options, use those instead  */
+		spin_lock(&gfs2_sys_margs_lock);
+		if (gfs2_sys_margs) {
+			data = gfs2_sys_margs;
+			gfs2_sys_margs = NULL;
+		}
+		spin_unlock(&gfs2_sys_margs_lock);
+
+		/*  Set some defaults  */
+		args->ar_num_glockd = GFS2_GLOCKD_DEFAULT;
+		args->ar_quota = GFS2_QUOTA_DEFAULT;
+		args->ar_data = GFS2_DATA_DEFAULT;
+	}
+
+	/* Split the options into tokens with the "," character and
+	   process them */
+
+	for (options = data; (o = strsep(&options, ",")); ) {
+		if (!*o)
+			continue;
+
+		v = strchr(o, '=');
+		if (v)
+			*v++ = 0;
+
+		if (!strcmp(o, "lockproto")) {
+			if (!v)
+				goto need_value;
+			if (remount && strcmp(v, args->ar_lockproto))
+				goto cant_remount;
+			strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
+			args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
+		}
+
+		else if (!strcmp(o, "locktable")) {
+			if (!v)
+				goto need_value;
+			if (remount && strcmp(v, args->ar_locktable))
+				goto cant_remount;
+			strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
+			args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
+		}
+
+		else if (!strcmp(o, "hostdata")) {
+			if (!v)
+				goto need_value;
+			if (remount && strcmp(v, args->ar_hostdata))
+				goto cant_remount;
+			strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
+			args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
+		}
+
+		else if (!strcmp(o, "spectator")) {
+			if (remount && !args->ar_spectator)
+				goto cant_remount;
+			args->ar_spectator = 1;
+			sdp->sd_vfs->s_flags |= MS_RDONLY;
+		}
+
+		else if (!strcmp(o, "ignore_local_fs")) {
+			if (remount && !args->ar_ignore_local_fs)
+				goto cant_remount;
+			args->ar_ignore_local_fs = 1;
+		}
+
+		else if (!strcmp(o, "localflocks")) {
+			if (remount && !args->ar_localflocks)
+				goto cant_remount;
+			args->ar_localflocks = 1;
+		}
+
+		else if (!strcmp(o, "localcaching")) {
+			if (remount && !args->ar_localcaching)
+				goto cant_remount;
+			args->ar_localcaching = 1;
+		}
+
+		else if (!strcmp(o, "debug"))
+			args->ar_debug = 1;
+
+		else if (!strcmp(o, "nodebug"))
+			args->ar_debug = 0;
+
+		else if (!strcmp(o, "upgrade")) {
+			if (remount && !args->ar_upgrade)
+				goto cant_remount;
+			args->ar_upgrade = 1;
+		}
+
+		else if (!strcmp(o, "num_glockd")) {
+			unsigned int x;
+			if (!v)
+				goto need_value;
+			sscanf(v, "%u", &x);
+			if (remount && x != args->ar_num_glockd)
+				goto cant_remount;
+			if (!x || x > GFS2_GLOCKD_MAX) {
+				fs_info(sdp, "0 < num_glockd <= %u  (not %u)\n",
+				        GFS2_GLOCKD_MAX, x);
+				error = -EINVAL;
+				break;
+			}
+			args->ar_num_glockd = x;
+		}
+
+		else if (!strcmp(o, "acl")) {
+			args->ar_posix_acl = 1;
+			sdp->sd_vfs->s_flags |= MS_POSIXACL;
+		}
+
+		else if (!strcmp(o, "noacl")) {
+			args->ar_posix_acl = 0;
+			sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
+		}
+
+		else if (!strcmp(o, "quota")) {
+			if (!v)
+				goto need_value;
+			if (!strcmp(v, "off"))
+				args->ar_quota = GFS2_QUOTA_OFF;
+			else if (!strcmp(v, "account"))
+				args->ar_quota = GFS2_QUOTA_ACCOUNT;
+			else if (!strcmp(v, "on"))
+				args->ar_quota = GFS2_QUOTA_ON;
+			else {
+				fs_info(sdp, "invalid value for quota\n");
+				error = -EINVAL;
+				break;
+			}
+		}
+
+		else if (!strcmp(o, "suiddir"))
+			args->ar_suiddir = 1;
+
+		else if (!strcmp(o, "nosuiddir"))
+			args->ar_suiddir = 0;
+
+		else if (!strcmp(o, "data")) {
+			if (!v)
+				goto need_value;
+			if (!strcmp(v, "writeback"))
+				args->ar_data = GFS2_DATA_WRITEBACK;
+			else if (!strcmp(v, "ordered"))
+				args->ar_data = GFS2_DATA_ORDERED;
+			else {
+				fs_info(sdp, "invalid value for data\n");
+				error = -EINVAL;
+				break;
+			}
+		}
+
+		else {
+			fs_info(sdp, "unknown option: %s\n", o);
+			error = -EINVAL;
+			break;
+		}
+	}
+
+	if (error)
+		fs_info(sdp, "invalid mount option(s)\n");
+
+	if (data != data_arg)
+		kfree(data);
+
+	return error;
+
+need_value:
+	fs_info(sdp, "need value for option %s\n", o);
+	return -EINVAL;
+
+cant_remount:
+	fs_info(sdp, "can't remount with option %s\n", o);
+	return -EINVAL;
+}
+
diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h
new file mode 100644
index 0000000..401288a
--- /dev/null
+++ b/fs/gfs2/mount.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __MOUNT_DOT_H__
+#define __MOUNT_DOT_H__
+
+struct gfs2_sbd;
+
+int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount);
+
+#endif /* __MOUNT_DOT_H__ */
diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c
new file mode 100644
index 0000000..1025960
--- /dev/null
+++ b/fs/gfs2/ondisk.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+
+#include "gfs2.h"
+#include <linux/gfs2_ondisk.h>
+
+#define pv(struct, member, fmt) printk(KERN_INFO "  "#member" = "fmt"\n", \
+				       struct->member);
+
+/*
+ * gfs2_xxx_in - read in an xxx struct
+ * first arg: the cpu-order structure
+ * buf: the disk-order buffer
+ *
+ * gfs2_xxx_out - write out an xxx struct
+ * first arg: the cpu-order structure
+ * buf: the disk-order buffer
+ *
+ * gfs2_xxx_print - print out an xxx struct
+ * first arg: the cpu-order structure
+ */
+
+void gfs2_inum_in(struct gfs2_inum *no, const void *buf)
+{
+	const struct gfs2_inum *str = buf;
+
+	no->no_formal_ino = be64_to_cpu(str->no_formal_ino);
+	no->no_addr = be64_to_cpu(str->no_addr);
+}
+
+void gfs2_inum_out(const struct gfs2_inum *no, void *buf)
+{
+	struct gfs2_inum *str = buf;
+
+	str->no_formal_ino = cpu_to_be64(no->no_formal_ino);
+	str->no_addr = cpu_to_be64(no->no_addr);
+}
+
+static void gfs2_inum_print(const struct gfs2_inum *no)
+{
+	printk(KERN_INFO "  no_formal_ino = %llu\n", (unsigned long long)no->no_formal_ino);
+	printk(KERN_INFO "  no_addr = %llu\n", (unsigned long long)no->no_addr);
+}
+
+static void gfs2_meta_header_in(struct gfs2_meta_header *mh, const void *buf)
+{
+	const struct gfs2_meta_header *str = buf;
+
+	mh->mh_magic = be32_to_cpu(str->mh_magic);
+	mh->mh_type = be32_to_cpu(str->mh_type);
+	mh->mh_format = be32_to_cpu(str->mh_format);
+}
+
+static void gfs2_meta_header_out(const struct gfs2_meta_header *mh, void *buf)
+{
+	struct gfs2_meta_header *str = buf;
+
+	str->mh_magic = cpu_to_be32(mh->mh_magic);
+	str->mh_type = cpu_to_be32(mh->mh_type);
+	str->mh_format = cpu_to_be32(mh->mh_format);
+}
+
+static void gfs2_meta_header_print(const struct gfs2_meta_header *mh)
+{
+	pv(mh, mh_magic, "0x%.8X");
+	pv(mh, mh_type, "%u");
+	pv(mh, mh_format, "%u");
+}
+
+void gfs2_sb_in(struct gfs2_sb *sb, const void *buf)
+{
+	const struct gfs2_sb *str = buf;
+
+	gfs2_meta_header_in(&sb->sb_header, buf);
+
+	sb->sb_fs_format = be32_to_cpu(str->sb_fs_format);
+	sb->sb_multihost_format = be32_to_cpu(str->sb_multihost_format);
+	sb->sb_bsize = be32_to_cpu(str->sb_bsize);
+	sb->sb_bsize_shift = be32_to_cpu(str->sb_bsize_shift);
+
+	gfs2_inum_in(&sb->sb_master_dir, (char *)&str->sb_master_dir);
+	gfs2_inum_in(&sb->sb_root_dir, (char *)&str->sb_root_dir);
+
+	memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
+	memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
+}
+
+void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf)
+{
+	const struct gfs2_rindex *str = buf;
+
+	ri->ri_addr = be64_to_cpu(str->ri_addr);
+	ri->ri_length = be32_to_cpu(str->ri_length);
+	ri->ri_data0 = be64_to_cpu(str->ri_data0);
+	ri->ri_data = be32_to_cpu(str->ri_data);
+	ri->ri_bitbytes = be32_to_cpu(str->ri_bitbytes);
+
+}
+
+void gfs2_rindex_print(const struct gfs2_rindex *ri)
+{
+	printk(KERN_INFO "  ri_addr = %llu\n", (unsigned long long)ri->ri_addr);
+	pv(ri, ri_length, "%u");
+
+	printk(KERN_INFO "  ri_data0 = %llu\n", (unsigned long long)ri->ri_data0);
+	pv(ri, ri_data, "%u");
+
+	pv(ri, ri_bitbytes, "%u");
+}
+
+void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf)
+{
+	const struct gfs2_rgrp *str = buf;
+
+	gfs2_meta_header_in(&rg->rg_header, buf);
+	rg->rg_flags = be32_to_cpu(str->rg_flags);
+	rg->rg_free = be32_to_cpu(str->rg_free);
+	rg->rg_dinodes = be32_to_cpu(str->rg_dinodes);
+	rg->rg_igeneration = be64_to_cpu(str->rg_igeneration);
+}
+
+void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf)
+{
+	struct gfs2_rgrp *str = buf;
+
+	gfs2_meta_header_out(&rg->rg_header, buf);
+	str->rg_flags = cpu_to_be32(rg->rg_flags);
+	str->rg_free = cpu_to_be32(rg->rg_free);
+	str->rg_dinodes = cpu_to_be32(rg->rg_dinodes);
+	str->__pad = cpu_to_be32(0);
+	str->rg_igeneration = cpu_to_be64(rg->rg_igeneration);
+	memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));
+}
+
+void gfs2_quota_in(struct gfs2_quota *qu, const void *buf)
+{
+	const struct gfs2_quota *str = buf;
+
+	qu->qu_limit = be64_to_cpu(str->qu_limit);
+	qu->qu_warn = be64_to_cpu(str->qu_warn);
+	qu->qu_value = be64_to_cpu(str->qu_value);
+}
+
+void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf)
+{
+	const struct gfs2_dinode *str = buf;
+
+	gfs2_meta_header_in(&di->di_header, buf);
+	gfs2_inum_in(&di->di_num, &str->di_num);
+
+	di->di_mode = be32_to_cpu(str->di_mode);
+	di->di_uid = be32_to_cpu(str->di_uid);
+	di->di_gid = be32_to_cpu(str->di_gid);
+	di->di_nlink = be32_to_cpu(str->di_nlink);
+	di->di_size = be64_to_cpu(str->di_size);
+	di->di_blocks = be64_to_cpu(str->di_blocks);
+	di->di_atime = be64_to_cpu(str->di_atime);
+	di->di_mtime = be64_to_cpu(str->di_mtime);
+	di->di_ctime = be64_to_cpu(str->di_ctime);
+	di->di_major = be32_to_cpu(str->di_major);
+	di->di_minor = be32_to_cpu(str->di_minor);
+
+	di->di_goal_meta = be64_to_cpu(str->di_goal_meta);
+	di->di_goal_data = be64_to_cpu(str->di_goal_data);
+	di->di_generation = be64_to_cpu(str->di_generation);
+
+	di->di_flags = be32_to_cpu(str->di_flags);
+	di->di_payload_format = be32_to_cpu(str->di_payload_format);
+	di->di_height = be16_to_cpu(str->di_height);
+
+	di->di_depth = be16_to_cpu(str->di_depth);
+	di->di_entries = be32_to_cpu(str->di_entries);
+
+	di->di_eattr = be64_to_cpu(str->di_eattr);
+
+}
+
+void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf)
+{
+	struct gfs2_dinode *str = buf;
+
+	gfs2_meta_header_out(&di->di_header, buf);
+	gfs2_inum_out(&di->di_num, (char *)&str->di_num);
+
+	str->di_mode = cpu_to_be32(di->di_mode);
+	str->di_uid = cpu_to_be32(di->di_uid);
+	str->di_gid = cpu_to_be32(di->di_gid);
+	str->di_nlink = cpu_to_be32(di->di_nlink);
+	str->di_size = cpu_to_be64(di->di_size);
+	str->di_blocks = cpu_to_be64(di->di_blocks);
+	str->di_atime = cpu_to_be64(di->di_atime);
+	str->di_mtime = cpu_to_be64(di->di_mtime);
+	str->di_ctime = cpu_to_be64(di->di_ctime);
+	str->di_major = cpu_to_be32(di->di_major);
+	str->di_minor = cpu_to_be32(di->di_minor);
+
+	str->di_goal_meta = cpu_to_be64(di->di_goal_meta);
+	str->di_goal_data = cpu_to_be64(di->di_goal_data);
+	str->di_generation = cpu_to_be64(di->di_generation);
+
+	str->di_flags = cpu_to_be32(di->di_flags);
+	str->di_payload_format = cpu_to_be32(di->di_payload_format);
+	str->di_height = cpu_to_be16(di->di_height);
+
+	str->di_depth = cpu_to_be16(di->di_depth);
+	str->di_entries = cpu_to_be32(di->di_entries);
+
+	str->di_eattr = cpu_to_be64(di->di_eattr);
+
+}
+
+void gfs2_dinode_print(const struct gfs2_dinode *di)
+{
+	gfs2_meta_header_print(&di->di_header);
+	gfs2_inum_print(&di->di_num);
+
+	pv(di, di_mode, "0%o");
+	pv(di, di_uid, "%u");
+	pv(di, di_gid, "%u");
+	pv(di, di_nlink, "%u");
+	printk(KERN_INFO "  di_size = %llu\n", (unsigned long long)di->di_size);
+	printk(KERN_INFO "  di_blocks = %llu\n", (unsigned long long)di->di_blocks);
+	printk(KERN_INFO "  di_atime = %lld\n", (long long)di->di_atime);
+	printk(KERN_INFO "  di_mtime = %lld\n", (long long)di->di_mtime);
+	printk(KERN_INFO "  di_ctime = %lld\n", (long long)di->di_ctime);
+	pv(di, di_major, "%u");
+	pv(di, di_minor, "%u");
+
+	printk(KERN_INFO "  di_goal_meta = %llu\n", (unsigned long long)di->di_goal_meta);
+	printk(KERN_INFO "  di_goal_data = %llu\n", (unsigned long long)di->di_goal_data);
+
+	pv(di, di_flags, "0x%.8X");
+	pv(di, di_payload_format, "%u");
+	pv(di, di_height, "%u");
+
+	pv(di, di_depth, "%u");
+	pv(di, di_entries, "%u");
+
+	printk(KERN_INFO "  di_eattr = %llu\n", (unsigned long long)di->di_eattr);
+}
+
+void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf)
+{
+	const struct gfs2_log_header *str = buf;
+
+	gfs2_meta_header_in(&lh->lh_header, buf);
+	lh->lh_sequence = be64_to_cpu(str->lh_sequence);
+	lh->lh_flags = be32_to_cpu(str->lh_flags);
+	lh->lh_tail = be32_to_cpu(str->lh_tail);
+	lh->lh_blkno = be32_to_cpu(str->lh_blkno);
+	lh->lh_hash = be32_to_cpu(str->lh_hash);
+}
+
+void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf)
+{
+	const struct gfs2_inum_range *str = buf;
+
+	ir->ir_start = be64_to_cpu(str->ir_start);
+	ir->ir_length = be64_to_cpu(str->ir_length);
+}
+
+void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf)
+{
+	struct gfs2_inum_range *str = buf;
+
+	str->ir_start = cpu_to_be64(ir->ir_start);
+	str->ir_length = cpu_to_be64(ir->ir_length);
+}
+
+void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf)
+{
+	const struct gfs2_statfs_change *str = buf;
+
+	sc->sc_total = be64_to_cpu(str->sc_total);
+	sc->sc_free = be64_to_cpu(str->sc_free);
+	sc->sc_dinodes = be64_to_cpu(str->sc_dinodes);
+}
+
+void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf)
+{
+	struct gfs2_statfs_change *str = buf;
+
+	str->sc_total = cpu_to_be64(sc->sc_total);
+	str->sc_free = cpu_to_be64(sc->sc_free);
+	str->sc_dinodes = cpu_to_be64(sc->sc_dinodes);
+}
+
+void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf)
+{
+	const struct gfs2_quota_change *str = buf;
+
+	qc->qc_change = be64_to_cpu(str->qc_change);
+	qc->qc_flags = be32_to_cpu(str->qc_flags);
+	qc->qc_id = be32_to_cpu(str->qc_id);
+}
+
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
new file mode 100644
index 0000000..4fb743f
--- /dev/null
+++ b/fs/gfs2/ops_address.c
@@ -0,0 +1,790 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/pagemap.h>
+#include <linux/pagevec.h>
+#include <linux/mpage.h>
+#include <linux/fs.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "ops_address.h"
+#include "quota.h"
+#include "trans.h"
+#include "rgrp.h"
+#include "ops_file.h"
+#include "util.h"
+#include "glops.h"
+
+
+static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
+				   unsigned int from, unsigned int to)
+{
+	struct buffer_head *head = page_buffers(page);
+	unsigned int bsize = head->b_size;
+	struct buffer_head *bh;
+	unsigned int start, end;
+
+	for (bh = head, start = 0; bh != head || !start;
+	     bh = bh->b_this_page, start = end) {
+		end = start + bsize;
+		if (end <= from || start >= to)
+			continue;
+		gfs2_trans_add_bh(ip->i_gl, bh, 0);
+	}
+}
+
+/**
+ * gfs2_get_block - Fills in a buffer head with details about a block
+ * @inode: The inode
+ * @lblock: The block number to look up
+ * @bh_result: The buffer head to return the result in
+ * @create: Non-zero if we may add block to the file
+ *
+ * Returns: errno
+ */
+
+int gfs2_get_block(struct inode *inode, sector_t lblock,
+	           struct buffer_head *bh_result, int create)
+{
+	return gfs2_block_map(inode, lblock, create, bh_result, 32);
+}
+
+/**
+ * gfs2_get_block_noalloc - Fills in a buffer head with details about a block
+ * @inode: The inode
+ * @lblock: The block number to look up
+ * @bh_result: The buffer head to return the result in
+ * @create: Non-zero if we may add block to the file
+ *
+ * Returns: errno
+ */
+
+static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
+				  struct buffer_head *bh_result, int create)
+{
+	int error;
+
+	error = gfs2_block_map(inode, lblock, 0, bh_result, 1);
+	if (error)
+		return error;
+	if (bh_result->b_blocknr == 0)
+		return -EIO;
+	return 0;
+}
+
+static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
+				 struct buffer_head *bh_result, int create)
+{
+	return gfs2_block_map(inode, lblock, 0, bh_result, 32);
+}
+
+/**
+ * gfs2_writepage - Write complete page
+ * @page: Page to write
+ *
+ * Returns: errno
+ *
+ * Some of this is copied from block_write_full_page() although we still
+ * call it to do most of the work.
+ */
+
+static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
+{
+	struct inode *inode = page->mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	loff_t i_size = i_size_read(inode);
+	pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+	unsigned offset;
+	int error;
+	int done_trans = 0;
+
+	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) {
+		unlock_page(page);
+		return -EIO;
+	}
+	if (current->journal_info)
+		goto out_ignore;
+
+	/* Is the page fully outside i_size? (truncate in progress) */
+        offset = i_size & (PAGE_CACHE_SIZE-1);
+	if (page->index > end_index || (page->index == end_index && !offset)) {
+		page->mapping->a_ops->invalidatepage(page, 0);
+		unlock_page(page);
+		return 0; /* don't care */
+	}
+
+	if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) {
+		error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
+		if (error)
+			goto out_ignore;
+		if (!page_has_buffers(page)) {
+			create_empty_buffers(page, inode->i_sb->s_blocksize,
+					     (1 << BH_Dirty)|(1 << BH_Uptodate));
+		}
+		gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
+		done_trans = 1;
+	}
+	error = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
+	if (done_trans)
+		gfs2_trans_end(sdp);
+	gfs2_meta_cache_flush(ip);
+	return error;
+
+out_ignore:
+	redirty_page_for_writepage(wbc, page);
+	unlock_page(page);
+	return 0;
+}
+
+static int zero_readpage(struct page *page)
+{
+	void *kaddr;
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	memset(kaddr, 0, PAGE_CACHE_SIZE);
+	kunmap_atomic(page, KM_USER0);
+
+	SetPageUptodate(page);
+
+	return 0;
+}
+
+/**
+ * stuffed_readpage - Fill in a Linux page with stuffed file data
+ * @ip: the inode
+ * @page: the page
+ *
+ * Returns: errno
+ */
+
+static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
+{
+	struct buffer_head *dibh;
+	void *kaddr;
+	int error;
+
+	/* Only the first page of a stuffed file might contain data */
+	if (unlikely(page->index))
+		return zero_readpage(page);
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		return error;
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
+	       ip->i_di.di_size);
+	memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
+	kunmap_atomic(page, KM_USER0);
+
+	brelse(dibh);
+
+	SetPageUptodate(page);
+
+	return 0;
+}
+
+
+/**
+ * gfs2_readpage - readpage with locking
+ * @file: The file to read a page for. N.B. This may be NULL if we are
+ * reading an internal file.
+ * @page: The page to read
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readpage(struct file *file, struct page *page)
+{
+	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+	struct gfs2_file *gf = NULL;
+	struct gfs2_holder gh;
+	int error;
+	int do_unlock = 0;
+
+	if (likely(file != &gfs2_internal_file_sentinel)) {
+		if (file) {
+			gf = file->private_data;
+			if (test_bit(GFF_EXLOCK, &gf->f_flags))
+				/* gfs2_sharewrite_nopage has grabbed the ip->i_gl already */
+				goto skip_lock;
+		}
+		gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh);
+		do_unlock = 1;
+		error = gfs2_glock_nq_m_atime(1, &gh);
+		if (unlikely(error))
+			goto out_unlock;
+	}
+
+skip_lock:
+	if (gfs2_is_stuffed(ip)) {
+		error = stuffed_readpage(ip, page);
+		unlock_page(page);
+	} else
+		error = mpage_readpage(page, gfs2_get_block);
+
+	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		error = -EIO;
+
+	if (do_unlock) {
+		gfs2_glock_dq_m(1, &gh);
+		gfs2_holder_uninit(&gh);
+	}
+out:
+	return error;
+out_unlock:
+	unlock_page(page);
+	if (do_unlock)
+		gfs2_holder_uninit(&gh);
+	goto out;
+}
+
+/**
+ * gfs2_readpages - Read a bunch of pages at once
+ *
+ * Some notes:
+ * 1. This is only for readahead, so we can simply ignore any things
+ *    which are slightly inconvenient (such as locking conflicts between
+ *    the page lock and the glock) and return having done no I/O. Its
+ *    obviously not something we'd want to do on too regular a basis.
+ *    Any I/O we ignore at this time will be done via readpage later.
+ * 2. We have to handle stuffed files here too.
+ * 3. mpage_readpages() does most of the heavy lifting in the common case.
+ * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
+ * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
+ *    well as read-ahead.
+ */
+static int gfs2_readpages(struct file *file, struct address_space *mapping,
+			  struct list_head *pages, unsigned nr_pages)
+{
+	struct inode *inode = mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct gfs2_holder gh;
+	unsigned page_idx;
+	int ret;
+	int do_unlock = 0;
+
+	if (likely(file != &gfs2_internal_file_sentinel)) {
+		if (file) {
+			struct gfs2_file *gf = file->private_data;
+			if (test_bit(GFF_EXLOCK, &gf->f_flags))
+				goto skip_lock;
+		}
+		gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
+				 LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh);
+		do_unlock = 1;
+		ret = gfs2_glock_nq_m_atime(1, &gh);
+		if (ret == GLR_TRYFAILED)
+			goto out_noerror;
+		if (unlikely(ret))
+			goto out_unlock;
+	}
+skip_lock:
+	if (gfs2_is_stuffed(ip)) {
+		struct pagevec lru_pvec;
+		pagevec_init(&lru_pvec, 0);
+		for (page_idx = 0; page_idx < nr_pages; page_idx++) {
+			struct page *page = list_entry(pages->prev, struct page, lru);
+			prefetchw(&page->flags);
+			list_del(&page->lru);
+			if (!add_to_page_cache(page, mapping,
+					       page->index, GFP_KERNEL)) {
+				ret = stuffed_readpage(ip, page);
+				unlock_page(page);
+				if (!pagevec_add(&lru_pvec, page))
+					 __pagevec_lru_add(&lru_pvec);
+			} else {
+				page_cache_release(page);
+			}
+		}
+		pagevec_lru_add(&lru_pvec);
+		ret = 0;
+	} else {
+		/* What we really want to do .... */
+		ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
+	}
+
+	if (do_unlock) {
+		gfs2_glock_dq_m(1, &gh);
+		gfs2_holder_uninit(&gh);
+	}
+out:
+	if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+		ret = -EIO;
+	return ret;
+out_noerror:
+	ret = 0;
+out_unlock:
+	/* unlock all pages, we can't do any I/O right now */
+	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
+		struct page *page = list_entry(pages->prev, struct page, lru);
+		list_del(&page->lru);
+		unlock_page(page);
+		page_cache_release(page);
+	}
+	if (do_unlock)
+		gfs2_holder_uninit(&gh);
+	goto out;
+}
+
+/**
+ * gfs2_prepare_write - Prepare to write a page to a file
+ * @file: The file to write to
+ * @page: The page which is to be prepared for writing
+ * @from: From (byte range within page)
+ * @to: To (byte range within page)
+ *
+ * Returns: errno
+ */
+
+static int gfs2_prepare_write(struct file *file, struct page *page,
+			      unsigned from, unsigned to)
+{
+	struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+	unsigned int data_blocks, ind_blocks, rblocks;
+	int alloc_required;
+	int error = 0;
+	loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from;
+	loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+	struct gfs2_alloc *al;
+
+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|GL_AOP, &ip->i_gh);
+	error = gfs2_glock_nq_m_atime(1, &ip->i_gh);
+	if (error)
+		goto out_uninit;
+
+	gfs2_write_calc_reserv(ip, to - from, &data_blocks, &ind_blocks);
+
+	error = gfs2_write_alloc_required(ip, pos, from - to, &alloc_required);
+	if (error)
+		goto out_unlock;
+
+
+	if (alloc_required) {
+		al = gfs2_alloc_get(ip);
+
+		error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+		if (error)
+			goto out_alloc_put;
+
+		error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+		if (error)
+			goto out_qunlock;
+
+		al->al_requested = data_blocks + ind_blocks;
+		error = gfs2_inplace_reserve(ip);
+		if (error)
+			goto out_qunlock;
+	}
+
+	rblocks = RES_DINODE + ind_blocks;
+	if (gfs2_is_jdata(ip))
+		rblocks += data_blocks ? data_blocks : 1;
+	if (ind_blocks || data_blocks)
+		rblocks += RES_STATFS + RES_QUOTA;
+
+	error = gfs2_trans_begin(sdp, rblocks, 0);
+	if (error)
+		goto out;
+
+	if (gfs2_is_stuffed(ip)) {
+		if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
+			error = gfs2_unstuff_dinode(ip, page);
+			if (error == 0)
+				goto prepare_write;
+		} else if (!PageUptodate(page))
+			error = stuffed_readpage(ip, page);
+		goto out;
+	}
+
+prepare_write:
+	error = block_prepare_write(page, from, to, gfs2_get_block);
+
+out:
+	if (error) {
+		gfs2_trans_end(sdp);
+		if (alloc_required) {
+			gfs2_inplace_release(ip);
+out_qunlock:
+			gfs2_quota_unlock(ip);
+out_alloc_put:
+			gfs2_alloc_put(ip);
+		}
+out_unlock:
+		gfs2_glock_dq_m(1, &ip->i_gh);
+out_uninit:
+		gfs2_holder_uninit(&ip->i_gh);
+	}
+
+	return error;
+}
+
+/**
+ * gfs2_commit_write - Commit write to a file
+ * @file: The file to write to
+ * @page: The page containing the data
+ * @from: From (byte range within page)
+ * @to: To (byte range within page)
+ *
+ * Returns: errno
+ */
+
+static int gfs2_commit_write(struct file *file, struct page *page,
+			     unsigned from, unsigned to)
+{
+	struct inode *inode = page->mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	int error = -EOPNOTSUPP;
+	struct buffer_head *dibh;
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_dinode *di;
+
+	if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)))
+                goto fail_nounlock;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto fail_endtrans;
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	di = (struct gfs2_dinode *)dibh->b_data;
+
+	if (gfs2_is_stuffed(ip)) {
+		u64 file_size;
+		void *kaddr;
+
+		file_size = ((u64)page->index << PAGE_CACHE_SHIFT) + to;
+
+		kaddr = kmap_atomic(page, KM_USER0);
+		memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from,
+		       kaddr + from, to - from);
+		kunmap_atomic(page, KM_USER0);
+
+		SetPageUptodate(page);
+
+		if (inode->i_size < file_size)
+			i_size_write(inode, file_size);
+	} else {
+		if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED ||
+		    gfs2_is_jdata(ip))
+			gfs2_page_add_databufs(ip, page, from, to);
+		error = generic_commit_write(file, page, from, to);
+		if (error)
+			goto fail;
+	}
+
+	if (ip->i_di.di_size < inode->i_size) {
+		ip->i_di.di_size = inode->i_size;
+		di->di_size = cpu_to_be64(inode->i_size);
+	}
+
+	di->di_mode = cpu_to_be32(inode->i_mode);
+	di->di_atime = cpu_to_be64(inode->i_atime.tv_sec);
+	di->di_mtime = cpu_to_be64(inode->i_mtime.tv_sec);
+	di->di_ctime = cpu_to_be64(inode->i_ctime.tv_sec);
+
+	brelse(dibh);
+	gfs2_trans_end(sdp);
+	if (al->al_requested) {
+		gfs2_inplace_release(ip);
+		gfs2_quota_unlock(ip);
+		gfs2_alloc_put(ip);
+	}
+	gfs2_glock_dq_m(1, &ip->i_gh);
+	gfs2_holder_uninit(&ip->i_gh);
+	return 0;
+
+fail:
+	brelse(dibh);
+fail_endtrans:
+	gfs2_trans_end(sdp);
+	if (al->al_requested) {
+		gfs2_inplace_release(ip);
+		gfs2_quota_unlock(ip);
+		gfs2_alloc_put(ip);
+	}
+	gfs2_glock_dq_m(1, &ip->i_gh);
+	gfs2_holder_uninit(&ip->i_gh);
+fail_nounlock:
+	ClearPageUptodate(page);
+	return error;
+}
+
+/**
+ * gfs2_bmap - Block map function
+ * @mapping: Address space info
+ * @lblock: The block to map
+ *
+ * Returns: The disk address for the block or 0 on hole or error
+ */
+
+static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
+{
+	struct gfs2_inode *ip = GFS2_I(mapping->host);
+	struct gfs2_holder i_gh;
+	sector_t dblock = 0;
+	int error;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+	if (error)
+		return 0;
+
+	if (!gfs2_is_stuffed(ip))
+		dblock = generic_block_bmap(mapping, lblock, gfs2_get_block);
+
+	gfs2_glock_dq_uninit(&i_gh);
+
+	return dblock;
+}
+
+static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+	struct gfs2_bufdata *bd;
+
+	gfs2_log_lock(sdp);
+	bd = bh->b_private;
+	if (bd) {
+		bd->bd_bh = NULL;
+		bh->b_private = NULL;
+	}
+	gfs2_log_unlock(sdp);
+
+	lock_buffer(bh);
+	clear_buffer_dirty(bh);
+	bh->b_bdev = NULL;
+	clear_buffer_mapped(bh);
+	clear_buffer_req(bh);
+	clear_buffer_new(bh);
+	clear_buffer_delay(bh);
+	unlock_buffer(bh);
+}
+
+static void gfs2_invalidatepage(struct page *page, unsigned long offset)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+	struct buffer_head *head, *bh, *next;
+	unsigned int curr_off = 0;
+
+	BUG_ON(!PageLocked(page));
+	if (!page_has_buffers(page))
+		return;
+
+	bh = head = page_buffers(page);
+	do {
+		unsigned int next_off = curr_off + bh->b_size;
+		next = bh->b_this_page;
+
+		if (offset <= curr_off)
+			discard_buffer(sdp, bh);
+
+		curr_off = next_off;
+		bh = next;
+	} while (bh != head);
+
+	if (!offset)
+		try_to_release_page(page, 0);
+
+	return;
+}
+
+static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
+			      const struct iovec *iov, loff_t offset,
+			      unsigned long nr_segs)
+{
+	struct file *file = iocb->ki_filp;
+	struct inode *inode = file->f_mapping->host;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder gh;
+	int rv;
+
+	if (rw == READ)
+		mutex_lock(&inode->i_mutex);
+	/*
+	 * Shared lock, even if its a write, since we do no allocation
+	 * on this path. All we need change is atime.
+	 */
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+	rv = gfs2_glock_nq_m_atime(1, &gh);
+	if (rv)
+		goto out;
+
+	if (offset > i_size_read(inode))
+		goto out;
+
+	/*
+	 * Should we return an error here? I can't see that O_DIRECT for
+	 * a journaled file makes any sense. For now we'll silently fall
+	 * back to buffered I/O, likewise we do the same for stuffed
+	 * files since they are (a) small and (b) unaligned.
+	 */
+	if (gfs2_is_jdata(ip))
+		goto out;
+
+	if (gfs2_is_stuffed(ip))
+		goto out;
+
+	rv = blockdev_direct_IO_own_locking(rw, iocb, inode,
+					    inode->i_sb->s_bdev,
+					    iov, offset, nr_segs,
+					    gfs2_get_block_direct, NULL);
+out:
+	gfs2_glock_dq_m(1, &gh);
+	gfs2_holder_uninit(&gh);
+	if (rw == READ)
+		mutex_unlock(&inode->i_mutex);
+
+	return rv;
+}
+
+/**
+ * stuck_releasepage - We're stuck in gfs2_releasepage().  Print stuff out.
+ * @bh: the buffer we're stuck on
+ *
+ */
+
+static void stuck_releasepage(struct buffer_head *bh)
+{
+	struct inode *inode = bh->b_page->mapping->host;
+	struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+	struct gfs2_bufdata *bd = bh->b_private;
+	struct gfs2_glock *gl;
+static unsigned limit = 0;
+
+	if (limit > 3)
+		return;
+	limit++;
+
+	fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
+	fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
+		(unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
+	fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
+	fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
+
+	if (!bd)
+		return;
+
+	gl = bd->bd_gl;
+
+	fs_warn(sdp, "gl = (%u, %llu)\n",
+		gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
+
+	fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
+		(list_empty(&bd->bd_list_tr)) ? "no" : "yes",
+		(list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
+
+	if (gl->gl_ops == &gfs2_inode_glops) {
+		struct gfs2_inode *ip = gl->gl_object;
+		unsigned int x;
+
+		if (!ip)
+			return;
+
+		fs_warn(sdp, "ip = %llu %llu\n",
+			(unsigned long long)ip->i_num.no_formal_ino,
+			(unsigned long long)ip->i_num.no_addr);
+
+		for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
+			fs_warn(sdp, "ip->i_cache[%u] = %s\n",
+				x, (ip->i_cache[x]) ? "!NULL" : "NULL");
+	}
+}
+
+/**
+ * gfs2_releasepage - free the metadata associated with a page
+ * @page: the page that's being released
+ * @gfp_mask: passed from Linux VFS, ignored by us
+ *
+ * Call try_to_free_buffers() if the buffers in this page can be
+ * released.
+ *
+ * Returns: 0
+ */
+
+int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
+{
+	struct inode *aspace = page->mapping->host;
+	struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
+	struct buffer_head *bh, *head;
+	struct gfs2_bufdata *bd;
+	unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ;
+
+	if (!page_has_buffers(page))
+		goto out;
+
+	head = bh = page_buffers(page);
+	do {
+		while (atomic_read(&bh->b_count)) {
+			if (!atomic_read(&aspace->i_writecount))
+				return 0;
+
+			if (time_after_eq(jiffies, t)) {
+				stuck_releasepage(bh);
+				/* should we withdraw here? */
+				return 0;
+			}
+
+			yield();
+		}
+
+		gfs2_assert_warn(sdp, !buffer_pinned(bh));
+		gfs2_assert_warn(sdp, !buffer_dirty(bh));
+
+		gfs2_log_lock(sdp);
+		bd = bh->b_private;
+		if (bd) {
+			gfs2_assert_warn(sdp, bd->bd_bh == bh);
+			gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
+			gfs2_assert_warn(sdp, !bd->bd_ail);
+			bd->bd_bh = NULL;
+			if (!list_empty(&bd->bd_le.le_list))
+				bd = NULL;
+			bh->b_private = NULL;
+		}
+		gfs2_log_unlock(sdp);
+		if (bd)
+			kmem_cache_free(gfs2_bufdata_cachep, bd);
+
+		bh = bh->b_this_page;
+	} while (bh != head);
+
+out:
+	return try_to_free_buffers(page);
+}
+
+const struct address_space_operations gfs2_file_aops = {
+	.writepage = gfs2_writepage,
+	.readpage = gfs2_readpage,
+	.readpages = gfs2_readpages,
+	.sync_page = block_sync_page,
+	.prepare_write = gfs2_prepare_write,
+	.commit_write = gfs2_commit_write,
+	.bmap = gfs2_bmap,
+	.invalidatepage = gfs2_invalidatepage,
+	.releasepage = gfs2_releasepage,
+	.direct_IO = gfs2_direct_IO,
+};
+
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
new file mode 100644
index 0000000..35aaee4
--- /dev/null
+++ b/fs/gfs2/ops_address.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_ADDRESS_DOT_H__
+#define __OPS_ADDRESS_DOT_H__
+
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/mm.h>
+
+extern const struct address_space_operations gfs2_file_aops;
+extern int gfs2_get_block(struct inode *inode, sector_t lblock,
+			  struct buffer_head *bh_result, int create);
+extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
+
+#endif /* __OPS_ADDRESS_DOT_H__ */
diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
new file mode 100644
index 0000000..00041b1
--- /dev/null
+++ b/fs/gfs2/ops_dentry.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/smp_lock.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "dir.h"
+#include "glock.h"
+#include "ops_dentry.h"
+#include "util.h"
+
+/**
+ * gfs2_drevalidate - Check directory lookup consistency
+ * @dentry: the mapping to check
+ * @nd:
+ *
+ * Check to make sure the lookup necessary to arrive at this inode from its
+ * parent is still good.
+ *
+ * Returns: 1 if the dentry is ok, 0 if it isn't
+ */
+
+static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
+{
+	struct dentry *parent = dget_parent(dentry);
+	struct gfs2_sbd *sdp = GFS2_SB(parent->d_inode);
+	struct gfs2_inode *dip = GFS2_I(parent->d_inode);
+	struct inode *inode = dentry->d_inode;
+	struct gfs2_holder d_gh;
+	struct gfs2_inode *ip;
+	struct gfs2_inum inum;
+	unsigned int type;
+	int error;
+
+	if (inode && is_bad_inode(inode))
+		goto invalid;
+
+	if (sdp->sd_args.ar_localcaching)
+		goto valid;
+
+	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+	if (error)
+		goto fail;
+
+	error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type);
+	switch (error) {
+	case 0:
+		if (!inode)
+			goto invalid_gunlock;
+		break;
+	case -ENOENT:
+		if (!inode)
+			goto valid_gunlock;
+		goto invalid_gunlock;
+	default:
+		goto fail_gunlock;
+	}
+
+	ip = GFS2_I(inode);
+
+	if (!gfs2_inum_equal(&ip->i_num, &inum))
+		goto invalid_gunlock;
+
+	if (IF2DT(ip->i_di.di_mode) != type) {
+		gfs2_consist_inode(dip);
+		goto fail_gunlock;
+	}
+
+valid_gunlock:
+	gfs2_glock_dq_uninit(&d_gh);
+valid:
+	dput(parent);
+	return 1;
+
+invalid_gunlock:
+	gfs2_glock_dq_uninit(&d_gh);
+invalid:
+	if (inode && S_ISDIR(inode->i_mode)) {
+		if (have_submounts(dentry))
+			goto valid;
+		shrink_dcache_parent(dentry);
+	}
+	d_drop(dentry);
+	dput(parent);
+	return 0;
+
+fail_gunlock:
+	gfs2_glock_dq_uninit(&d_gh);
+fail:
+	dput(parent);
+	return 0;
+}
+
+static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
+{
+	str->hash = gfs2_disk_hash(str->name, str->len);
+	return 0;
+}
+
+struct dentry_operations gfs2_dops = {
+	.d_revalidate = gfs2_drevalidate,
+	.d_hash = gfs2_dhash,
+};
+
diff --git a/fs/gfs2/ops_dentry.h b/fs/gfs2/ops_dentry.h
new file mode 100644
index 0000000..5caa3db
--- /dev/null
+++ b/fs/gfs2/ops_dentry.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_DENTRY_DOT_H__
+#define __OPS_DENTRY_DOT_H__
+
+#include <linux/dcache.h>
+
+extern struct dentry_operations gfs2_dops;
+
+#endif /* __OPS_DENTRY_DOT_H__ */
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
new file mode 100644
index 0000000..86127d9
--- /dev/null
+++ b/fs/gfs2/ops_export.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "dir.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "ops_export.h"
+#include "rgrp.h"
+#include "util.h"
+
+static struct dentry *gfs2_decode_fh(struct super_block *sb,
+				     __u32 *fh,
+				     int fh_len,
+				     int fh_type,
+				     int (*acceptable)(void *context,
+						       struct dentry *dentry),
+				     void *context)
+{
+	struct gfs2_fh_obj fh_obj;
+	struct gfs2_inum *this, parent;
+
+	if (fh_type != fh_len)
+		return NULL;
+
+	this 		= &fh_obj.this;
+	fh_obj.imode 	= DT_UNKNOWN;
+	memset(&parent, 0, sizeof(struct gfs2_inum));
+
+	switch (fh_type) {
+	case GFS2_LARGE_FH_SIZE:
+		parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
+		parent.no_formal_ino |= be32_to_cpu(fh[5]);
+		parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
+		parent.no_addr |= be32_to_cpu(fh[7]);
+		fh_obj.imode = be32_to_cpu(fh[8]);
+	case GFS2_SMALL_FH_SIZE:
+		this->no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
+		this->no_formal_ino |= be32_to_cpu(fh[1]);
+		this->no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
+		this->no_addr |= be32_to_cpu(fh[3]);
+		break;
+	default:
+		return NULL;
+	}
+
+	return gfs2_export_ops.find_exported_dentry(sb, &fh_obj, &parent,
+						    acceptable, context);
+}
+
+static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
+			  int connectable)
+{
+	struct inode *inode = dentry->d_inode;
+	struct super_block *sb = inode->i_sb;
+	struct gfs2_inode *ip = GFS2_I(inode);
+
+	if (*len < GFS2_SMALL_FH_SIZE ||
+	    (connectable && *len < GFS2_LARGE_FH_SIZE))
+		return 255;
+
+	fh[0] = ip->i_num.no_formal_ino >> 32;
+	fh[0] = cpu_to_be32(fh[0]);
+	fh[1] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
+	fh[1] = cpu_to_be32(fh[1]);
+	fh[2] = ip->i_num.no_addr >> 32;
+	fh[2] = cpu_to_be32(fh[2]);
+	fh[3] = ip->i_num.no_addr & 0xFFFFFFFF;
+	fh[3] = cpu_to_be32(fh[3]);
+	*len = GFS2_SMALL_FH_SIZE;
+
+	if (!connectable || inode == sb->s_root->d_inode)
+		return *len;
+
+	spin_lock(&dentry->d_lock);
+	inode = dentry->d_parent->d_inode;
+	ip = GFS2_I(inode);
+	igrab(inode);
+	spin_unlock(&dentry->d_lock);
+
+	fh[4] = ip->i_num.no_formal_ino >> 32;
+	fh[4] = cpu_to_be32(fh[4]);
+	fh[5] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
+	fh[5] = cpu_to_be32(fh[5]);
+	fh[6] = ip->i_num.no_addr >> 32;
+	fh[6] = cpu_to_be32(fh[6]);
+	fh[7] = ip->i_num.no_addr & 0xFFFFFFFF;
+	fh[7] = cpu_to_be32(fh[7]);
+
+	fh[8]  = cpu_to_be32(inode->i_mode);
+	fh[9]  = 0;	/* pad to double word */
+	*len = GFS2_LARGE_FH_SIZE;
+
+	iput(inode);
+
+	return *len;
+}
+
+struct get_name_filldir {
+	struct gfs2_inum inum;
+	char *name;
+};
+
+static int get_name_filldir(void *opaque, const char *name, unsigned int length,
+			    u64 offset, struct gfs2_inum *inum,
+			    unsigned int type)
+{
+	struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;
+
+	if (!gfs2_inum_equal(inum, &gnfd->inum))
+		return 0;
+
+	memcpy(gnfd->name, name, length);
+	gnfd->name[length] = 0;
+
+	return 1;
+}
+
+static int gfs2_get_name(struct dentry *parent, char *name,
+			 struct dentry *child)
+{
+	struct inode *dir = parent->d_inode;
+	struct inode *inode = child->d_inode;
+	struct gfs2_inode *dip, *ip;
+	struct get_name_filldir gnfd;
+	struct gfs2_holder gh;
+	u64 offset = 0;
+	int error;
+
+	if (!dir)
+		return -EINVAL;
+
+	if (!S_ISDIR(dir->i_mode) || !inode)
+		return -EINVAL;
+
+	dip = GFS2_I(dir);
+	ip = GFS2_I(inode);
+
+	*name = 0;
+	gnfd.inum = ip->i_num;
+	gnfd.name = name;
+
+	error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
+	if (error)
+		return error;
+
+	error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
+
+	gfs2_glock_dq_uninit(&gh);
+
+	if (!error && !*name)
+		error = -ENOENT;
+
+	return error;
+}
+
+static struct dentry *gfs2_get_parent(struct dentry *child)
+{
+	struct qstr dotdot;
+	struct inode *inode;
+	struct dentry *dentry;
+
+	gfs2_str2qstr(&dotdot, "..");
+	inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);
+
+	if (!inode)
+		return ERR_PTR(-ENOENT);
+	/*
+	 * In case of an error, @inode carries the error value, and we
+	 * have to return that as a(n invalid) pointer to dentry.
+	 */
+	if (IS_ERR(inode))
+		return ERR_PTR(PTR_ERR(inode));
+
+	dentry = d_alloc_anon(inode);
+	if (!dentry) {
+		iput(inode);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return dentry;
+}
+
+static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj;
+	struct gfs2_inum *inum = &fh_obj->this;
+	struct gfs2_holder i_gh, ri_gh, rgd_gh;
+	struct gfs2_rgrpd *rgd;
+	struct inode *inode;
+	struct dentry *dentry;
+	int error;
+
+	/* System files? */
+
+	inode = gfs2_ilookup(sb, inum);
+	if (inode) {
+		if (GFS2_I(inode)->i_num.no_formal_ino != inum->no_formal_ino) {
+			iput(inode);
+			return ERR_PTR(-ESTALE);
+		}
+		goto out_inode;
+	}
+
+	error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
+				  LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
+				  &i_gh);
+	if (error)
+		return ERR_PTR(error);
+
+	error = gfs2_rindex_hold(sdp, &ri_gh);
+	if (error)
+		goto fail;
+
+	error = -EINVAL;
+	rgd = gfs2_blk2rgrpd(sdp, inum->no_addr);
+	if (!rgd)
+		goto fail_rindex;
+
+	error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
+	if (error)
+		goto fail_rindex;
+
+	error = -ESTALE;
+	if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE)
+		goto fail_rgd;
+
+	gfs2_glock_dq_uninit(&rgd_gh);
+	gfs2_glock_dq_uninit(&ri_gh);
+
+	inode = gfs2_inode_lookup(sb, inum, fh_obj->imode);
+	if (!inode)
+		goto fail;
+	if (IS_ERR(inode)) {
+		error = PTR_ERR(inode);
+		goto fail;
+	}
+
+	error = gfs2_inode_refresh(GFS2_I(inode));
+	if (error) {
+		iput(inode);
+		goto fail;
+	}
+
+	error = -EIO;
+	if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) {
+		iput(inode);
+		goto fail;
+	}
+
+	gfs2_glock_dq_uninit(&i_gh);
+
+out_inode:
+	dentry = d_alloc_anon(inode);
+	if (!dentry) {
+		iput(inode);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return dentry;
+
+fail_rgd:
+	gfs2_glock_dq_uninit(&rgd_gh);
+
+fail_rindex:
+	gfs2_glock_dq_uninit(&ri_gh);
+
+fail:
+	gfs2_glock_dq_uninit(&i_gh);
+	return ERR_PTR(error);
+}
+
+struct export_operations gfs2_export_ops = {
+	.decode_fh = gfs2_decode_fh,
+	.encode_fh = gfs2_encode_fh,
+	.get_name = gfs2_get_name,
+	.get_parent = gfs2_get_parent,
+	.get_dentry = gfs2_get_dentry,
+};
+
diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h
new file mode 100644
index 0000000..09aca50
--- /dev/null
+++ b/fs/gfs2/ops_export.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_EXPORT_DOT_H__
+#define __OPS_EXPORT_DOT_H__
+
+#define GFS2_SMALL_FH_SIZE 4
+#define GFS2_LARGE_FH_SIZE 10
+
+extern struct export_operations gfs2_export_ops;
+struct gfs2_fh_obj {
+	struct gfs2_inum this;
+	__u32            imode;
+};
+
+#endif /* __OPS_EXPORT_DOT_H__ */
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
new file mode 100644
index 0000000..3064f13
--- /dev/null
+++ b/fs/gfs2/ops_file.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/pagemap.h>
+#include <linux/uio.h>
+#include <linux/blkdev.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/fs.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/ext2_fs.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "dir.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "lm.h"
+#include "log.h"
+#include "meta_io.h"
+#include "ops_file.h"
+#include "ops_vm.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+#include "eaops.h"
+
+/* For regular, non-NFS */
+struct filldir_reg {
+	struct gfs2_sbd *fdr_sbd;
+	int fdr_prefetch;
+
+	filldir_t fdr_filldir;
+	void *fdr_opaque;
+};
+
+/*
+ * Most fields left uninitialised to catch anybody who tries to
+ * use them. f_flags set to prevent file_accessed() from touching
+ * any other part of this. Its use is purely as a flag so that we
+ * know (in readpage()) whether or not do to locking.
+ */
+struct file gfs2_internal_file_sentinel = {
+	.f_flags = O_NOATIME|O_RDONLY,
+};
+
+static int gfs2_read_actor(read_descriptor_t *desc, struct page *page,
+			   unsigned long offset, unsigned long size)
+{
+	char *kaddr;
+	unsigned long count = desc->count;
+
+	if (size > count)
+		size = count;
+
+	kaddr = kmap(page);
+	memcpy(desc->arg.buf, kaddr + offset, size);
+	kunmap(page);
+
+	desc->count = count - size;
+	desc->written += size;
+	desc->arg.buf += size;
+	return size;
+}
+
+int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
+		       char *buf, loff_t *pos, unsigned size)
+{
+	struct inode *inode = &ip->i_inode;
+	read_descriptor_t desc;
+	desc.written = 0;
+	desc.arg.buf = buf;
+	desc.count = size;
+	desc.error = 0;
+	do_generic_mapping_read(inode->i_mapping, ra_state,
+				&gfs2_internal_file_sentinel, pos, &desc,
+				gfs2_read_actor);
+	return desc.written ? desc.written : desc.error;
+}
+
+/**
+ * gfs2_llseek - seek to a location in a file
+ * @file: the file
+ * @offset: the offset
+ * @origin: Where to seek from (SEEK_SET, SEEK_CUR, or SEEK_END)
+ *
+ * SEEK_END requires the glock for the file because it references the
+ * file's size.
+ *
+ * Returns: The new offset, or errno
+ */
+
+static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
+{
+	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+	struct gfs2_holder i_gh;
+	loff_t error;
+
+	if (origin == 2) {
+		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
+					   &i_gh);
+		if (!error) {
+			error = remote_llseek(file, offset, origin);
+			gfs2_glock_dq_uninit(&i_gh);
+		}
+	} else
+		error = remote_llseek(file, offset, origin);
+
+	return error;
+}
+
+/**
+ * filldir_func - Report a directory entry to the caller of gfs2_dir_read()
+ * @opaque: opaque data used by the function
+ * @name: the name of the directory entry
+ * @length: the length of the name
+ * @offset: the entry's offset in the directory
+ * @inum: the inode number the entry points to
+ * @type: the type of inode the entry points to
+ *
+ * Returns: 0 on success, 1 if buffer full
+ */
+
+static int filldir_func(void *opaque, const char *name, unsigned int length,
+			u64 offset, struct gfs2_inum *inum,
+			unsigned int type)
+{
+	struct filldir_reg *fdr = (struct filldir_reg *)opaque;
+	struct gfs2_sbd *sdp = fdr->fdr_sbd;
+	int error;
+
+	error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset,
+				 inum->no_addr, type);
+	if (error)
+		return 1;
+
+	if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) {
+		gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops,
+				       LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY);
+		gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops,
+				       LM_ST_SHARED, LM_FLAG_TRY);
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_readdir - Read directory entries from a directory
+ * @file: The directory to read from
+ * @dirent: Buffer for dirents
+ * @filldir: Function used to do the copying
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+	struct inode *dir = file->f_mapping->host;
+	struct gfs2_inode *dip = GFS2_I(dir);
+	struct filldir_reg fdr;
+	struct gfs2_holder d_gh;
+	u64 offset = file->f_pos;
+	int error;
+
+	fdr.fdr_sbd = GFS2_SB(dir);
+	fdr.fdr_prefetch = 1;
+	fdr.fdr_filldir = filldir;
+	fdr.fdr_opaque = dirent;
+
+	gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh);
+	error = gfs2_glock_nq_atime(&d_gh);
+	if (error) {
+		gfs2_holder_uninit(&d_gh);
+		return error;
+	}
+
+	error = gfs2_dir_read(dir, &offset, &fdr, filldir_func);
+
+	gfs2_glock_dq_uninit(&d_gh);
+
+	file->f_pos = offset;
+
+	return error;
+}
+
+/**
+ * fsflags_cvt
+ * @table: A table of 32 u32 flags
+ * @val: a 32 bit value to convert
+ *
+ * This function can be used to convert between fsflags values and
+ * GFS2's own flags values.
+ *
+ * Returns: the converted flags
+ */
+static u32 fsflags_cvt(const u32 *table, u32 val)
+{
+	u32 res = 0;
+	while(val) {
+		if (val & 1)
+			res |= *table;
+		table++;
+		val >>= 1;
+	}
+	return res;
+}
+
+static const u32 fsflags_to_gfs2[32] = {
+	[3] = GFS2_DIF_SYNC,
+	[4] = GFS2_DIF_IMMUTABLE,
+	[5] = GFS2_DIF_APPENDONLY,
+	[7] = GFS2_DIF_NOATIME,
+	[12] = GFS2_DIF_EXHASH,
+	[14] = GFS2_DIF_JDATA,
+	[20] = GFS2_DIF_DIRECTIO,
+};
+
+static const u32 gfs2_to_fsflags[32] = {
+	[gfs2fl_Sync] = FS_SYNC_FL,
+	[gfs2fl_Immutable] = FS_IMMUTABLE_FL,
+	[gfs2fl_AppendOnly] = FS_APPEND_FL,
+	[gfs2fl_NoAtime] = FS_NOATIME_FL,
+	[gfs2fl_ExHash] = FS_INDEX_FL,
+	[gfs2fl_Jdata] = FS_JOURNAL_DATA_FL,
+	[gfs2fl_Directio] = FS_DIRECTIO_FL,
+	[gfs2fl_InheritDirectio] = FS_DIRECTIO_FL,
+	[gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL,
+};
+
+static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder gh;
+	int error;
+	u32 fsflags;
+
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+	error = gfs2_glock_nq_m_atime(1, &gh);
+	if (error)
+		return error;
+
+	fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_di.di_flags);
+	if (put_user(fsflags, ptr))
+		error = -EFAULT;
+
+	gfs2_glock_dq_m(1, &gh);
+	gfs2_holder_uninit(&gh);
+	return error;
+}
+
+/* Flags that can be set by user space */
+#define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA|			\
+			     GFS2_DIF_DIRECTIO|			\
+			     GFS2_DIF_IMMUTABLE|		\
+			     GFS2_DIF_APPENDONLY|		\
+			     GFS2_DIF_NOATIME|			\
+			     GFS2_DIF_SYNC|			\
+			     GFS2_DIF_SYSTEM|			\
+			     GFS2_DIF_INHERIT_DIRECTIO|		\
+			     GFS2_DIF_INHERIT_JDATA)
+
+/**
+ * gfs2_set_flags - set flags on an inode
+ * @inode: The inode
+ * @flags: The flags to set
+ * @mask: Indicates which flags are valid
+ *
+ */
+static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
+{
+	struct inode *inode = filp->f_dentry->d_inode;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct buffer_head *bh;
+	struct gfs2_holder gh;
+	int error;
+	u32 new_flags, flags;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+	if (error)
+		return error;
+
+	flags = ip->i_di.di_flags;
+	new_flags = (flags & ~mask) | (reqflags & mask);
+	if ((new_flags ^ flags) == 0)
+		goto out;
+
+	if (S_ISDIR(inode->i_mode)) {
+		if ((new_flags ^ flags) & GFS2_DIF_JDATA)
+			new_flags ^= (GFS2_DIF_JDATA|GFS2_DIF_INHERIT_JDATA);
+		if ((new_flags ^ flags) & GFS2_DIF_DIRECTIO)
+			new_flags ^= (GFS2_DIF_DIRECTIO|GFS2_DIF_INHERIT_DIRECTIO);
+	}
+
+	error = -EINVAL;
+	if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET)
+		goto out;
+
+	error = -EPERM;
+	if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE))
+		goto out;
+	if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY))
+		goto out;
+	if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) &&
+	    !capable(CAP_LINUX_IMMUTABLE))
+		goto out;
+	if (!IS_IMMUTABLE(inode)) {
+		error = permission(inode, MAY_WRITE, NULL);
+		if (error)
+			goto out;
+	}
+
+	error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+	if (error)
+		goto out;
+	error = gfs2_meta_inode_buffer(ip, &bh);
+	if (error)
+		goto out_trans_end;
+	gfs2_trans_add_bh(ip->i_gl, bh, 1);
+	ip->i_di.di_flags = new_flags;
+	gfs2_dinode_out(&ip->i_di, bh->b_data);
+	brelse(bh);
+out_trans_end:
+	gfs2_trans_end(sdp);
+out:
+	gfs2_glock_dq_uninit(&gh);
+	return error;
+}
+
+static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
+{
+	u32 fsflags, gfsflags;
+	if (get_user(fsflags, ptr))
+		return -EFAULT;
+	gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags);
+	return do_gfs2_set_flags(filp, gfsflags, ~0);
+}
+
+static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	switch(cmd) {
+	case FS_IOC_GETFLAGS:
+		return gfs2_get_flags(filp, (u32 __user *)arg);
+	case FS_IOC_SETFLAGS:
+		return gfs2_set_flags(filp, (u32 __user *)arg);
+	}
+	return -ENOTTY;
+}
+
+
+/**
+ * gfs2_mmap -
+ * @file: The file to map
+ * @vma: The VMA which described the mapping
+ *
+ * Returns: 0 or error code
+ */
+
+static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+	struct gfs2_holder i_gh;
+	int error;
+
+	gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh);
+	error = gfs2_glock_nq_atime(&i_gh);
+	if (error) {
+		gfs2_holder_uninit(&i_gh);
+		return error;
+	}
+
+	/* This is VM_MAYWRITE instead of VM_WRITE because a call
+	   to mprotect() can turn on VM_WRITE later. */
+
+	if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) ==
+	    (VM_MAYSHARE | VM_MAYWRITE))
+		vma->vm_ops = &gfs2_vm_ops_sharewrite;
+	else
+		vma->vm_ops = &gfs2_vm_ops_private;
+
+	gfs2_glock_dq_uninit(&i_gh);
+
+	return error;
+}
+
+/**
+ * gfs2_open - open a file
+ * @inode: the inode to open
+ * @file: the struct file for this opening
+ *
+ * Returns: errno
+ */
+
+static int gfs2_open(struct inode *inode, struct file *file)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder i_gh;
+	struct gfs2_file *fp;
+	int error;
+
+	fp = kzalloc(sizeof(struct gfs2_file), GFP_KERNEL);
+	if (!fp)
+		return -ENOMEM;
+
+	mutex_init(&fp->f_fl_mutex);
+
+	gfs2_assert_warn(GFS2_SB(inode), !file->private_data);
+	file->private_data = fp;
+
+	if (S_ISREG(ip->i_di.di_mode)) {
+		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
+					   &i_gh);
+		if (error)
+			goto fail;
+
+		if (!(file->f_flags & O_LARGEFILE) &&
+		    ip->i_di.di_size > MAX_NON_LFS) {
+			error = -EFBIG;
+			goto fail_gunlock;
+		}
+
+		/* Listen to the Direct I/O flag */
+
+		if (ip->i_di.di_flags & GFS2_DIF_DIRECTIO)
+			file->f_flags |= O_DIRECT;
+
+		gfs2_glock_dq_uninit(&i_gh);
+	}
+
+	return 0;
+
+fail_gunlock:
+	gfs2_glock_dq_uninit(&i_gh);
+fail:
+	file->private_data = NULL;
+	kfree(fp);
+	return error;
+}
+
+/**
+ * gfs2_close - called to close a struct file
+ * @inode: the inode the struct file belongs to
+ * @file: the struct file being closed
+ *
+ * Returns: errno
+ */
+
+static int gfs2_close(struct inode *inode, struct file *file)
+{
+	struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+	struct gfs2_file *fp;
+
+	fp = file->private_data;
+	file->private_data = NULL;
+
+	if (gfs2_assert_warn(sdp, fp))
+		return -EIO;
+
+	kfree(fp);
+
+	return 0;
+}
+
+/**
+ * gfs2_fsync - sync the dirty data for a file (across the cluster)
+ * @file: the file that points to the dentry (we ignore this)
+ * @dentry: the dentry that points to the inode to sync
+ *
+ * Returns: errno
+ */
+
+static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+
+	gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
+
+	return 0;
+}
+
+/**
+ * gfs2_lock - acquire/release a posix lock on a file
+ * @file: the file pointer
+ * @cmd: either modify or retrieve lock state, possibly wait
+ * @fl: type and range of lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+	struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
+	struct lm_lockname name =
+		{ .ln_number = ip->i_num.no_addr,
+		  .ln_type = LM_TYPE_PLOCK };
+
+	if (!(fl->fl_flags & FL_POSIX))
+		return -ENOLCK;
+	if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+		return -ENOLCK;
+
+	if (sdp->sd_args.ar_localflocks) {
+		if (IS_GETLK(cmd)) {
+			struct file_lock tmp;
+			int ret;
+			ret = posix_test_lock(file, fl, &tmp);
+			fl->fl_type = F_UNLCK;
+			if (ret)
+				memcpy(fl, &tmp, sizeof(struct file_lock));
+			return 0;
+		} else {
+			return posix_lock_file_wait(file, fl);
+		}
+	}
+
+	if (IS_GETLK(cmd))
+		return gfs2_lm_plock_get(sdp, &name, file, fl);
+	else if (fl->fl_type == F_UNLCK)
+		return gfs2_lm_punlock(sdp, &name, file, fl);
+	else
+		return gfs2_lm_plock(sdp, &name, file, cmd, fl);
+}
+
+static int do_flock(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct gfs2_file *fp = file->private_data;
+	struct gfs2_holder *fl_gh = &fp->f_fl_gh;
+	struct gfs2_inode *ip = GFS2_I(file->f_dentry->d_inode);
+	struct gfs2_glock *gl;
+	unsigned int state;
+	int flags;
+	int error = 0;
+
+	state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
+	flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE;
+
+	mutex_lock(&fp->f_fl_mutex);
+
+	gl = fl_gh->gh_gl;
+	if (gl) {
+		if (fl_gh->gh_state == state)
+			goto out;
+		gfs2_glock_hold(gl);
+		flock_lock_file_wait(file,
+				     &(struct file_lock){.fl_type = F_UNLCK});
+		gfs2_glock_dq_uninit(fl_gh);
+	} else {
+		error = gfs2_glock_get(GFS2_SB(&ip->i_inode),
+				      ip->i_num.no_addr, &gfs2_flock_glops,
+				      CREATE, &gl);
+		if (error)
+			goto out;
+	}
+
+	gfs2_holder_init(gl, state, flags, fl_gh);
+	gfs2_glock_put(gl);
+
+	error = gfs2_glock_nq(fl_gh);
+	if (error) {
+		gfs2_holder_uninit(fl_gh);
+		if (error == GLR_TRYFAILED)
+			error = -EAGAIN;
+	} else {
+		error = flock_lock_file_wait(file, fl);
+		gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
+	}
+
+out:
+	mutex_unlock(&fp->f_fl_mutex);
+	return error;
+}
+
+static void do_unflock(struct file *file, struct file_lock *fl)
+{
+	struct gfs2_file *fp = file->private_data;
+	struct gfs2_holder *fl_gh = &fp->f_fl_gh;
+
+	mutex_lock(&fp->f_fl_mutex);
+	flock_lock_file_wait(file, fl);
+	if (fl_gh->gh_gl)
+		gfs2_glock_dq_uninit(fl_gh);
+	mutex_unlock(&fp->f_fl_mutex);
+}
+
+/**
+ * gfs2_flock - acquire/release a flock lock on a file
+ * @file: the file pointer
+ * @cmd: either modify or retrieve lock state, possibly wait
+ * @fl: type and range of lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
+{
+	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+	struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
+
+	if (!(fl->fl_flags & FL_FLOCK))
+		return -ENOLCK;
+	if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+		return -ENOLCK;
+
+	if (sdp->sd_args.ar_localflocks)
+		return flock_lock_file_wait(file, fl);
+
+	if (fl->fl_type == F_UNLCK) {
+		do_unflock(file, fl);
+		return 0;
+	} else {
+		return do_flock(file, cmd, fl);
+	}
+}
+
+const struct file_operations gfs2_file_fops = {
+	.llseek		= gfs2_llseek,
+	.read		= do_sync_read,
+	.aio_read	= generic_file_aio_read,
+	.write		= do_sync_write,
+	.aio_write	= generic_file_aio_write,
+	.unlocked_ioctl	= gfs2_ioctl,
+	.mmap		= gfs2_mmap,
+	.open		= gfs2_open,
+	.release	= gfs2_close,
+	.fsync		= gfs2_fsync,
+	.lock		= gfs2_lock,
+	.sendfile	= generic_file_sendfile,
+	.flock		= gfs2_flock,
+	.splice_read	= generic_file_splice_read,
+	.splice_write	= generic_file_splice_write,
+};
+
+const struct file_operations gfs2_dir_fops = {
+	.readdir	= gfs2_readdir,
+	.unlocked_ioctl	= gfs2_ioctl,
+	.open		= gfs2_open,
+	.release	= gfs2_close,
+	.fsync		= gfs2_fsync,
+	.lock		= gfs2_lock,
+	.flock		= gfs2_flock,
+};
+
diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h
new file mode 100644
index 0000000..ce319f8
--- /dev/null
+++ b/fs/gfs2/ops_file.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_FILE_DOT_H__
+#define __OPS_FILE_DOT_H__
+
+#include <linux/fs.h>
+struct gfs2_inode;
+
+extern struct file gfs2_internal_file_sentinel;
+extern int gfs2_internal_read(struct gfs2_inode *ip,
+			      struct file_ra_state *ra_state,
+			      char *buf, loff_t *pos, unsigned size);
+
+extern const struct file_operations gfs2_file_fops;
+extern const struct file_operations gfs2_dir_fops;
+
+#endif /* __OPS_FILE_DOT_H__ */
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
new file mode 100644
index 0000000..178b339
--- /dev/null
+++ b/fs/gfs2/ops_fstype.c
@@ -0,0 +1,928 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "daemon.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "lm.h"
+#include "mount.h"
+#include "ops_export.h"
+#include "ops_fstype.h"
+#include "ops_super.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "super.h"
+#include "sys.h"
+#include "util.h"
+
+#define DO 0
+#define UNDO 1
+
+extern struct dentry_operations gfs2_dops;
+
+static struct gfs2_sbd *init_sbd(struct super_block *sb)
+{
+	struct gfs2_sbd *sdp;
+
+	sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL);
+	if (!sdp)
+		return NULL;
+
+	sb->s_fs_info = sdp;
+	sdp->sd_vfs = sb;
+
+	gfs2_tune_init(&sdp->sd_tune);
+
+	INIT_LIST_HEAD(&sdp->sd_reclaim_list);
+	spin_lock_init(&sdp->sd_reclaim_lock);
+	init_waitqueue_head(&sdp->sd_reclaim_wq);
+
+	mutex_init(&sdp->sd_inum_mutex);
+	spin_lock_init(&sdp->sd_statfs_spin);
+	mutex_init(&sdp->sd_statfs_mutex);
+
+	spin_lock_init(&sdp->sd_rindex_spin);
+	mutex_init(&sdp->sd_rindex_mutex);
+	INIT_LIST_HEAD(&sdp->sd_rindex_list);
+	INIT_LIST_HEAD(&sdp->sd_rindex_mru_list);
+	INIT_LIST_HEAD(&sdp->sd_rindex_recent_list);
+
+	INIT_LIST_HEAD(&sdp->sd_jindex_list);
+	spin_lock_init(&sdp->sd_jindex_spin);
+	mutex_init(&sdp->sd_jindex_mutex);
+
+	INIT_LIST_HEAD(&sdp->sd_quota_list);
+	spin_lock_init(&sdp->sd_quota_spin);
+	mutex_init(&sdp->sd_quota_mutex);
+
+	spin_lock_init(&sdp->sd_log_lock);
+
+	INIT_LIST_HEAD(&sdp->sd_log_le_gl);
+	INIT_LIST_HEAD(&sdp->sd_log_le_buf);
+	INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
+	INIT_LIST_HEAD(&sdp->sd_log_le_rg);
+	INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
+
+	mutex_init(&sdp->sd_log_reserve_mutex);
+	INIT_LIST_HEAD(&sdp->sd_ail1_list);
+	INIT_LIST_HEAD(&sdp->sd_ail2_list);
+
+	init_rwsem(&sdp->sd_log_flush_lock);
+	INIT_LIST_HEAD(&sdp->sd_log_flush_list);
+
+	INIT_LIST_HEAD(&sdp->sd_revoke_list);
+
+	mutex_init(&sdp->sd_freeze_lock);
+
+	return sdp;
+}
+
+static void init_vfs(struct super_block *sb, unsigned noatime)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+
+	sb->s_magic = GFS2_MAGIC;
+	sb->s_op = &gfs2_super_ops;
+	sb->s_export_op = &gfs2_export_ops;
+	sb->s_maxbytes = MAX_LFS_FILESIZE;
+
+	if (sb->s_flags & (MS_NOATIME | MS_NODIRATIME))
+		set_bit(noatime, &sdp->sd_flags);
+
+	/* Don't let the VFS update atimes.  GFS2 handles this itself. */
+	sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
+}
+
+static int init_names(struct gfs2_sbd *sdp, int silent)
+{
+	struct page *page;
+	char *proto, *table;
+	int error = 0;
+
+	proto = sdp->sd_args.ar_lockproto;
+	table = sdp->sd_args.ar_locktable;
+
+	/*  Try to autodetect  */
+
+	if (!proto[0] || !table[0]) {
+		struct gfs2_sb *sb;
+		page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
+		if (!page)
+			return -ENOBUFS;
+		sb = kmap(page);
+		gfs2_sb_in(&sdp->sd_sb, sb);
+		kunmap(page);
+		__free_page(page);
+
+		error = gfs2_check_sb(sdp, &sdp->sd_sb, silent);
+		if (error)
+			goto out;
+
+		if (!proto[0])
+			proto = sdp->sd_sb.sb_lockproto;
+		if (!table[0])
+			table = sdp->sd_sb.sb_locktable;
+	}
+
+	if (!table[0])
+		table = sdp->sd_vfs->s_id;
+
+	snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto);
+	snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table);
+
+out:
+	return error;
+}
+
+static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
+			int undo)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	if (undo)
+		goto fail_trans;
+
+	p = kthread_run(gfs2_scand, sdp, "gfs2_scand");
+	error = IS_ERR(p);
+	if (error) {
+		fs_err(sdp, "can't start scand thread: %d\n", error);
+		return error;
+	}
+	sdp->sd_scand_process = p;
+
+	for (sdp->sd_glockd_num = 0;
+	     sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd;
+	     sdp->sd_glockd_num++) {
+		p = kthread_run(gfs2_glockd, sdp, "gfs2_glockd");
+		error = IS_ERR(p);
+		if (error) {
+			fs_err(sdp, "can't start glockd thread: %d\n", error);
+			goto fail;
+		}
+		sdp->sd_glockd_process[sdp->sd_glockd_num] = p;
+	}
+
+	error = gfs2_glock_nq_num(sdp,
+				  GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
+				  LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE,
+				  mount_gh);
+	if (error) {
+		fs_err(sdp, "can't acquire mount glock: %d\n", error);
+		goto fail;
+	}
+
+	error = gfs2_glock_nq_num(sdp,
+				  GFS2_LIVE_LOCK, &gfs2_nondisk_glops,
+				  LM_ST_SHARED,
+				  LM_FLAG_NOEXP | GL_EXACT,
+				  &sdp->sd_live_gh);
+	if (error) {
+		fs_err(sdp, "can't acquire live glock: %d\n", error);
+		goto fail_mount;
+	}
+
+	error = gfs2_glock_get(sdp, GFS2_RENAME_LOCK, &gfs2_nondisk_glops,
+			       CREATE, &sdp->sd_rename_gl);
+	if (error) {
+		fs_err(sdp, "can't create rename glock: %d\n", error);
+		goto fail_live;
+	}
+
+	error = gfs2_glock_get(sdp, GFS2_TRANS_LOCK, &gfs2_trans_glops,
+			       CREATE, &sdp->sd_trans_gl);
+	if (error) {
+		fs_err(sdp, "can't create transaction glock: %d\n", error);
+		goto fail_rename;
+	}
+	set_bit(GLF_STICKY, &sdp->sd_trans_gl->gl_flags);
+
+	return 0;
+
+fail_trans:
+	gfs2_glock_put(sdp->sd_trans_gl);
+fail_rename:
+	gfs2_glock_put(sdp->sd_rename_gl);
+fail_live:
+	gfs2_glock_dq_uninit(&sdp->sd_live_gh);
+fail_mount:
+	gfs2_glock_dq_uninit(mount_gh);
+fail:
+	while (sdp->sd_glockd_num--)
+		kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
+
+	kthread_stop(sdp->sd_scand_process);
+	return error;
+}
+
+static struct inode *gfs2_lookup_root(struct super_block *sb,
+				      struct gfs2_inum *inum)
+{
+	return gfs2_inode_lookup(sb, inum, DT_DIR);
+}
+
+static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
+{
+	struct super_block *sb = sdp->sd_vfs;
+	struct gfs2_holder sb_gh;
+	struct gfs2_inum *inum;
+	struct inode *inode;
+	int error = 0;
+
+	if (undo) {
+		if (sb->s_root) {
+			dput(sb->s_root);
+			sb->s_root = NULL;
+		}
+		return 0;
+	}
+
+	error = gfs2_glock_nq_num(sdp, GFS2_SB_LOCK, &gfs2_meta_glops,
+				 LM_ST_SHARED, 0, &sb_gh);
+	if (error) {
+		fs_err(sdp, "can't acquire superblock glock: %d\n", error);
+		return error;
+	}
+
+	error = gfs2_read_sb(sdp, sb_gh.gh_gl, silent);
+	if (error) {
+		fs_err(sdp, "can't read superblock: %d\n", error);
+		goto out;
+	}
+
+	/* Set up the buffer cache and SB for real */
+	if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) {
+		error = -EINVAL;
+		fs_err(sdp, "FS block size (%u) is too small for device "
+		       "block size (%u)\n",
+		       sdp->sd_sb.sb_bsize, bdev_hardsect_size(sb->s_bdev));
+		goto out;
+	}
+	if (sdp->sd_sb.sb_bsize > PAGE_SIZE) {
+		error = -EINVAL;
+		fs_err(sdp, "FS block size (%u) is too big for machine "
+		       "page size (%u)\n",
+		       sdp->sd_sb.sb_bsize, (unsigned int)PAGE_SIZE);
+		goto out;
+	}
+	sb_set_blocksize(sb, sdp->sd_sb.sb_bsize);
+
+	/* Get the root inode */
+	inum = &sdp->sd_sb.sb_root_dir;
+	if (sb->s_type == &gfs2meta_fs_type)
+		inum = &sdp->sd_sb.sb_master_dir;
+	inode = gfs2_lookup_root(sb, inum);
+	if (IS_ERR(inode)) {
+		error = PTR_ERR(inode);
+		fs_err(sdp, "can't read in root inode: %d\n", error);
+		goto out;
+	}
+
+	sb->s_root = d_alloc_root(inode);
+	if (!sb->s_root) {
+		fs_err(sdp, "can't get root dentry\n");
+		error = -ENOMEM;
+		iput(inode);
+	}
+	sb->s_root->d_op = &gfs2_dops;
+out:
+	gfs2_glock_dq_uninit(&sb_gh);
+	return error;
+}
+
+static int init_journal(struct gfs2_sbd *sdp, int undo)
+{
+	struct gfs2_holder ji_gh;
+	struct task_struct *p;
+	struct gfs2_inode *ip;
+	int jindex = 1;
+	int error = 0;
+
+	if (undo) {
+		jindex = 0;
+		goto fail_recoverd;
+	}
+
+	sdp->sd_jindex = gfs2_lookup_simple(sdp->sd_master_dir, "jindex");
+	if (IS_ERR(sdp->sd_jindex)) {
+		fs_err(sdp, "can't lookup journal index: %d\n", error);
+		return PTR_ERR(sdp->sd_jindex);
+	}
+	ip = GFS2_I(sdp->sd_jindex);
+	set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
+
+	/* Load in the journal index special file */
+
+	error = gfs2_jindex_hold(sdp, &ji_gh);
+	if (error) {
+		fs_err(sdp, "can't read journal index: %d\n", error);
+		goto fail;
+	}
+
+	error = -EINVAL;
+	if (!gfs2_jindex_size(sdp)) {
+		fs_err(sdp, "no journals!\n");
+		goto fail_jindex;
+	}
+
+	if (sdp->sd_args.ar_spectator) {
+		sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
+		sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
+	} else {
+		if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) {
+			fs_err(sdp, "can't mount journal #%u\n",
+			       sdp->sd_lockstruct.ls_jid);
+			fs_err(sdp, "there are only %u journals (0 - %u)\n",
+			       gfs2_jindex_size(sdp),
+			       gfs2_jindex_size(sdp) - 1);
+			goto fail_jindex;
+		}
+		sdp->sd_jdesc = gfs2_jdesc_find(sdp, sdp->sd_lockstruct.ls_jid);
+
+		error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid,
+					  &gfs2_journal_glops,
+					  LM_ST_EXCLUSIVE, LM_FLAG_NOEXP,
+					  &sdp->sd_journal_gh);
+		if (error) {
+			fs_err(sdp, "can't acquire journal glock: %d\n", error);
+			goto fail_jindex;
+		}
+
+		ip = GFS2_I(sdp->sd_jdesc->jd_inode);
+		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
+					   LM_FLAG_NOEXP | GL_EXACT,
+					   &sdp->sd_jinode_gh);
+		if (error) {
+			fs_err(sdp, "can't acquire journal inode glock: %d\n",
+			       error);
+			goto fail_journal_gh;
+		}
+
+		error = gfs2_jdesc_check(sdp->sd_jdesc);
+		if (error) {
+			fs_err(sdp, "my journal (%u) is bad: %d\n",
+			       sdp->sd_jdesc->jd_jid, error);
+			goto fail_jinode_gh;
+		}
+		sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
+	}
+
+	if (sdp->sd_lockstruct.ls_first) {
+		unsigned int x;
+		for (x = 0; x < sdp->sd_journals; x++) {
+			error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x));
+			if (error) {
+				fs_err(sdp, "error recovering journal %u: %d\n",
+				       x, error);
+				goto fail_jinode_gh;
+			}
+		}
+
+		gfs2_lm_others_may_mount(sdp);
+	} else if (!sdp->sd_args.ar_spectator) {
+		error = gfs2_recover_journal(sdp->sd_jdesc);
+		if (error) {
+			fs_err(sdp, "error recovering my journal: %d\n", error);
+			goto fail_jinode_gh;
+		}
+	}
+
+	set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
+	gfs2_glock_dq_uninit(&ji_gh);
+	jindex = 0;
+
+	p = kthread_run(gfs2_recoverd, sdp, "gfs2_recoverd");
+	error = IS_ERR(p);
+	if (error) {
+		fs_err(sdp, "can't start recoverd thread: %d\n", error);
+		goto fail_jinode_gh;
+	}
+	sdp->sd_recoverd_process = p;
+
+	return 0;
+
+fail_recoverd:
+	kthread_stop(sdp->sd_recoverd_process);
+fail_jinode_gh:
+	if (!sdp->sd_args.ar_spectator)
+		gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
+fail_journal_gh:
+	if (!sdp->sd_args.ar_spectator)
+		gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
+fail_jindex:
+	gfs2_jindex_free(sdp);
+	if (jindex)
+		gfs2_glock_dq_uninit(&ji_gh);
+fail:
+	iput(sdp->sd_jindex);
+	return error;
+}
+
+
+static int init_inodes(struct gfs2_sbd *sdp, int undo)
+{
+	int error = 0;
+	struct gfs2_inode *ip;
+	struct inode *inode;
+
+	if (undo)
+		goto fail_qinode;
+
+	inode = gfs2_lookup_root(sdp->sd_vfs, &sdp->sd_sb.sb_master_dir);
+	if (IS_ERR(inode)) {
+		error = PTR_ERR(inode);
+		fs_err(sdp, "can't read in master directory: %d\n", error);
+		goto fail;
+	}
+	sdp->sd_master_dir = inode;
+
+	error = init_journal(sdp, undo);
+	if (error)
+		goto fail_master;
+
+	/* Read in the master inode number inode */
+	sdp->sd_inum_inode = gfs2_lookup_simple(sdp->sd_master_dir, "inum");
+	if (IS_ERR(sdp->sd_inum_inode)) {
+		error = PTR_ERR(sdp->sd_inum_inode);
+		fs_err(sdp, "can't read in inum inode: %d\n", error);
+		goto fail_journal;
+	}
+
+
+	/* Read in the master statfs inode */
+	sdp->sd_statfs_inode = gfs2_lookup_simple(sdp->sd_master_dir, "statfs");
+	if (IS_ERR(sdp->sd_statfs_inode)) {
+		error = PTR_ERR(sdp->sd_statfs_inode);
+		fs_err(sdp, "can't read in statfs inode: %d\n", error);
+		goto fail_inum;
+	}
+
+	/* Read in the resource index inode */
+	sdp->sd_rindex = gfs2_lookup_simple(sdp->sd_master_dir, "rindex");
+	if (IS_ERR(sdp->sd_rindex)) {
+		error = PTR_ERR(sdp->sd_rindex);
+		fs_err(sdp, "can't get resource index inode: %d\n", error);
+		goto fail_statfs;
+	}
+	ip = GFS2_I(sdp->sd_rindex);
+	set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
+	sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1;
+
+	/* Read in the quota inode */
+	sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota");
+	if (IS_ERR(sdp->sd_quota_inode)) {
+		error = PTR_ERR(sdp->sd_quota_inode);
+		fs_err(sdp, "can't get quota file inode: %d\n", error);
+		goto fail_rindex;
+	}
+	return 0;
+
+fail_qinode:
+	iput(sdp->sd_quota_inode);
+fail_rindex:
+	gfs2_clear_rgrpd(sdp);
+	iput(sdp->sd_rindex);
+fail_statfs:
+	iput(sdp->sd_statfs_inode);
+fail_inum:
+	iput(sdp->sd_inum_inode);
+fail_journal:
+	init_journal(sdp, UNDO);
+fail_master:
+	iput(sdp->sd_master_dir);
+fail:
+	return error;
+}
+
+static int init_per_node(struct gfs2_sbd *sdp, int undo)
+{
+	struct inode *pn = NULL;
+	char buf[30];
+	int error = 0;
+	struct gfs2_inode *ip;
+
+	if (sdp->sd_args.ar_spectator)
+		return 0;
+
+	if (undo)
+		goto fail_qc_gh;
+
+	pn = gfs2_lookup_simple(sdp->sd_master_dir, "per_node");
+	if (IS_ERR(pn)) {
+		error = PTR_ERR(pn);
+		fs_err(sdp, "can't find per_node directory: %d\n", error);
+		return error;
+	}
+
+	sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid);
+	sdp->sd_ir_inode = gfs2_lookup_simple(pn, buf);
+	if (IS_ERR(sdp->sd_ir_inode)) {
+		error = PTR_ERR(sdp->sd_ir_inode);
+		fs_err(sdp, "can't find local \"ir\" file: %d\n", error);
+		goto fail;
+	}
+
+	sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid);
+	sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf);
+	if (IS_ERR(sdp->sd_sc_inode)) {
+		error = PTR_ERR(sdp->sd_sc_inode);
+		fs_err(sdp, "can't find local \"sc\" file: %d\n", error);
+		goto fail_ir_i;
+	}
+
+	sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid);
+	sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf);
+	if (IS_ERR(sdp->sd_qc_inode)) {
+		error = PTR_ERR(sdp->sd_qc_inode);
+		fs_err(sdp, "can't find local \"qc\" file: %d\n", error);
+		goto fail_ut_i;
+	}
+
+	iput(pn);
+	pn = NULL;
+
+	ip = GFS2_I(sdp->sd_ir_inode);
+	error = gfs2_glock_nq_init(ip->i_gl,
+				   LM_ST_EXCLUSIVE, 0,
+				   &sdp->sd_ir_gh);
+	if (error) {
+		fs_err(sdp, "can't lock local \"ir\" file: %d\n", error);
+		goto fail_qc_i;
+	}
+
+	ip = GFS2_I(sdp->sd_sc_inode);
+	error = gfs2_glock_nq_init(ip->i_gl,
+				   LM_ST_EXCLUSIVE, 0,
+				   &sdp->sd_sc_gh);
+	if (error) {
+		fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
+		goto fail_ir_gh;
+	}
+
+	ip = GFS2_I(sdp->sd_qc_inode);
+	error = gfs2_glock_nq_init(ip->i_gl,
+				   LM_ST_EXCLUSIVE, 0,
+				   &sdp->sd_qc_gh);
+	if (error) {
+		fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);
+		goto fail_ut_gh;
+	}
+
+	return 0;
+
+fail_qc_gh:
+	gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
+fail_ut_gh:
+	gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
+fail_ir_gh:
+	gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
+fail_qc_i:
+	iput(sdp->sd_qc_inode);
+fail_ut_i:
+	iput(sdp->sd_sc_inode);
+fail_ir_i:
+	iput(sdp->sd_ir_inode);
+fail:
+	if (pn)
+		iput(pn);
+	return error;
+}
+
+static int init_threads(struct gfs2_sbd *sdp, int undo)
+{
+	struct task_struct *p;
+	int error = 0;
+
+	if (undo)
+		goto fail_quotad;
+
+	sdp->sd_log_flush_time = jiffies;
+	sdp->sd_jindex_refresh_time = jiffies;
+
+	p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
+	error = IS_ERR(p);
+	if (error) {
+		fs_err(sdp, "can't start logd thread: %d\n", error);
+		return error;
+	}
+	sdp->sd_logd_process = p;
+
+	sdp->sd_statfs_sync_time = jiffies;
+	sdp->sd_quota_sync_time = jiffies;
+
+	p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
+	error = IS_ERR(p);
+	if (error) {
+		fs_err(sdp, "can't start quotad thread: %d\n", error);
+		goto fail;
+	}
+	sdp->sd_quotad_process = p;
+
+	return 0;
+
+
+fail_quotad:
+	kthread_stop(sdp->sd_quotad_process);
+fail:
+	kthread_stop(sdp->sd_logd_process);
+	return error;
+}
+
+/**
+ * fill_super - Read in superblock
+ * @sb: The VFS superblock
+ * @data: Mount options
+ * @silent: Don't complain if it's not a GFS2 filesystem
+ *
+ * Returns: errno
+ */
+
+static int fill_super(struct super_block *sb, void *data, int silent)
+{
+	struct gfs2_sbd *sdp;
+	struct gfs2_holder mount_gh;
+	int error;
+
+	sdp = init_sbd(sb);
+	if (!sdp) {
+		printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n");
+		return -ENOMEM;
+	}
+
+	error = gfs2_mount_args(sdp, (char *)data, 0);
+	if (error) {
+		printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
+		goto fail;
+	}
+
+	init_vfs(sb, SDF_NOATIME);
+
+	/* Set up the buffer cache and fill in some fake block size values
+	   to allow us to read-in the on-disk superblock. */
+	sdp->sd_sb.sb_bsize = sb_min_blocksize(sb, GFS2_BASIC_BLOCK);
+	sdp->sd_sb.sb_bsize_shift = sb->s_blocksize_bits;
+	sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
+                               GFS2_BASIC_BLOCK_SHIFT;
+	sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
+
+	error = init_names(sdp, silent);
+	if (error)
+		goto fail;
+
+	error = gfs2_sys_fs_add(sdp);
+	if (error)
+		goto fail;
+
+	error = gfs2_lm_mount(sdp, silent);
+	if (error)
+		goto fail_sys;
+
+	error = init_locking(sdp, &mount_gh, DO);
+	if (error)
+		goto fail_lm;
+
+	error = init_sb(sdp, silent, DO);
+	if (error)
+		goto fail_locking;
+
+	error = init_inodes(sdp, DO);
+	if (error)
+		goto fail_sb;
+
+	error = init_per_node(sdp, DO);
+	if (error)
+		goto fail_inodes;
+
+	error = gfs2_statfs_init(sdp);
+	if (error) {
+		fs_err(sdp, "can't initialize statfs subsystem: %d\n", error);
+		goto fail_per_node;
+	}
+
+	error = init_threads(sdp, DO);
+	if (error)
+		goto fail_per_node;
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		error = gfs2_make_fs_rw(sdp);
+		if (error) {
+			fs_err(sdp, "can't make FS RW: %d\n", error);
+			goto fail_threads;
+		}
+	}
+
+	gfs2_glock_dq_uninit(&mount_gh);
+
+	return 0;
+
+fail_threads:
+	init_threads(sdp, UNDO);
+fail_per_node:
+	init_per_node(sdp, UNDO);
+fail_inodes:
+	init_inodes(sdp, UNDO);
+fail_sb:
+	init_sb(sdp, 0, UNDO);
+fail_locking:
+	init_locking(sdp, &mount_gh, UNDO);
+fail_lm:
+	gfs2_gl_hash_clear(sdp, WAIT);
+	gfs2_lm_unmount(sdp);
+	while (invalidate_inodes(sb))
+		yield();
+fail_sys:
+	gfs2_sys_fs_del(sdp);
+fail:
+	kfree(sdp);
+	sb->s_fs_info = NULL;
+	return error;
+}
+
+static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
+		const char *dev_name, void *data, struct vfsmount *mnt)
+{
+	struct super_block *sb;
+	struct gfs2_sbd *sdp;
+	int error = get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt);
+	if (error)
+		goto out;
+	sb = mnt->mnt_sb;
+	sdp = sb->s_fs_info;
+	sdp->sd_gfs2mnt = mnt;
+out:
+	return error;
+}
+
+static int fill_super_meta(struct super_block *sb, struct super_block *new,
+			   void *data, int silent)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	struct inode *inode;
+	int error = 0;
+
+	new->s_fs_info = sdp;
+	sdp->sd_vfs_meta = sb;
+
+	init_vfs(new, SDF_NOATIME);
+
+        /* Get the master inode */
+	inode = igrab(sdp->sd_master_dir);
+
+	new->s_root = d_alloc_root(inode);
+	if (!new->s_root) {
+		fs_err(sdp, "can't get root dentry\n");
+		error = -ENOMEM;
+		iput(inode);
+	}
+	new->s_root->d_op = &gfs2_dops;
+
+	return error;
+}
+
+static int set_bdev_super(struct super_block *s, void *data)
+{
+	s->s_bdev = data;
+	s->s_dev = s->s_bdev->bd_dev;
+	return 0;
+}
+
+static int test_bdev_super(struct super_block *s, void *data)
+{
+	return s->s_bdev == data;
+}
+
+static struct super_block* get_gfs2_sb(const char *dev_name)
+{
+	struct kstat stat;
+	struct nameidata nd;
+	struct file_system_type *fstype;
+	struct super_block *sb = NULL, *s;
+	struct list_head *l;
+	int error;
+
+	error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+	if (error) {
+		printk(KERN_WARNING "GFS2: path_lookup on %s returned error\n",
+		       dev_name);
+		goto out;
+	}
+	error = vfs_getattr(nd.mnt, nd.dentry, &stat);
+
+	fstype = get_fs_type("gfs2");
+	list_for_each(l, &fstype->fs_supers) {
+		s = list_entry(l, struct super_block, s_instances);
+		if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
+		    (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) {
+			sb = s;
+			goto free_nd;
+		}
+	}
+
+	printk(KERN_WARNING "GFS2: Unrecognized block device or "
+	       "mount point %s", dev_name);
+
+free_nd:
+	path_release(&nd);
+out:
+	return sb;
+}
+
+static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
+			    const char *dev_name, void *data, struct vfsmount *mnt)
+{
+	int error = 0;
+	struct super_block *sb = NULL, *new;
+	struct gfs2_sbd *sdp;
+	char *gfs2mnt = NULL;
+
+	sb = get_gfs2_sb(dev_name);
+	if (!sb) {
+		printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
+		error = -ENOENT;
+		goto error;
+	}
+	sdp = (struct gfs2_sbd*) sb->s_fs_info;
+	if (sdp->sd_vfs_meta) {
+		printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n");
+		error = -EBUSY;
+		goto error;
+	}
+	mutex_lock(&sb->s_bdev->bd_mount_mutex);
+	new = sget(fs_type, test_bdev_super, set_bdev_super, sb->s_bdev);
+	mutex_unlock(&sb->s_bdev->bd_mount_mutex);
+	if (IS_ERR(new)) {
+		error = PTR_ERR(new);
+		goto error;
+	}
+	module_put(fs_type->owner);
+	new->s_flags = flags;
+	strlcpy(new->s_id, sb->s_id, sizeof(new->s_id));
+	sb_set_blocksize(new, sb->s_blocksize);
+	error = fill_super_meta(sb, new, data, flags & MS_SILENT ? 1 : 0);
+	if (error) {
+		up_write(&new->s_umount);
+		deactivate_super(new);
+		goto error;
+	}
+
+	new->s_flags |= MS_ACTIVE;
+
+	/* Grab a reference to the gfs2 mount point */
+	atomic_inc(&sdp->sd_gfs2mnt->mnt_count);
+	return simple_set_mnt(mnt, new);
+error:
+	if (gfs2mnt)
+		kfree(gfs2mnt);
+	return error;
+}
+
+static void gfs2_kill_sb(struct super_block *sb)
+{
+	kill_block_super(sb);
+}
+
+static void gfs2_kill_sb_meta(struct super_block *sb)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	generic_shutdown_super(sb);
+	sdp->sd_vfs_meta = NULL;
+	atomic_dec(&sdp->sd_gfs2mnt->mnt_count);
+}
+
+struct file_system_type gfs2_fs_type = {
+	.name = "gfs2",
+	.fs_flags = FS_REQUIRES_DEV,
+	.get_sb = gfs2_get_sb,
+	.kill_sb = gfs2_kill_sb,
+	.owner = THIS_MODULE,
+};
+
+struct file_system_type gfs2meta_fs_type = {
+	.name = "gfs2meta",
+	.fs_flags = FS_REQUIRES_DEV,
+	.get_sb = gfs2_get_sb_meta,
+	.kill_sb = gfs2_kill_sb_meta,
+	.owner = THIS_MODULE,
+};
+
diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h
new file mode 100644
index 0000000..7cc2c29
--- /dev/null
+++ b/fs/gfs2/ops_fstype.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_FSTYPE_DOT_H__
+#define __OPS_FSTYPE_DOT_H__
+
+#include <linux/fs.h>
+
+extern struct file_system_type gfs2_fs_type;
+extern struct file_system_type gfs2meta_fs_type;
+
+#endif /* __OPS_FSTYPE_DOT_H__ */
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
new file mode 100644
index 0000000..ef6e5ed
--- /dev/null
+++ b/fs/gfs2/ops_inode.c
@@ -0,0 +1,1151 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/namei.h>
+#include <linux/utsname.h>
+#include <linux/mm.h>
+#include <linux/xattr.h>
+#include <linux/posix_acl.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "bmap.h"
+#include "dir.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "ops_dentry.h"
+#include "ops_inode.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+/**
+ * gfs2_create - Create a file
+ * @dir: The directory in which to create the file
+ * @dentry: The dentry of the new file
+ * @mode: The mode of the new file
+ *
+ * Returns: errno
+ */
+
+static int gfs2_create(struct inode *dir, struct dentry *dentry,
+		       int mode, struct nameidata *nd)
+{
+	struct gfs2_inode *dip = GFS2_I(dir);
+	struct gfs2_sbd *sdp = GFS2_SB(dir);
+	struct gfs2_holder ghs[2];
+	struct inode *inode;
+
+	gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+	for (;;) {
+		inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode);
+		if (!IS_ERR(inode)) {
+			gfs2_trans_end(sdp);
+			if (dip->i_alloc.al_rgd)
+				gfs2_inplace_release(dip);
+			gfs2_quota_unlock(dip);
+			gfs2_alloc_put(dip);
+			gfs2_glock_dq_uninit_m(2, ghs);
+			mark_inode_dirty(inode);
+			break;
+		} else if (PTR_ERR(inode) != -EEXIST ||
+			   (nd->intent.open.flags & O_EXCL)) {
+			gfs2_holder_uninit(ghs);
+			return PTR_ERR(inode);
+		}
+
+		inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
+		if (inode) {
+			if (!IS_ERR(inode)) {
+				gfs2_holder_uninit(ghs);
+				break;
+			} else {
+				gfs2_holder_uninit(ghs);
+				return PTR_ERR(inode);
+			}
+		}
+	}
+
+	d_instantiate(dentry, inode);
+
+	return 0;
+}
+
+/**
+ * gfs2_lookup - Look up a filename in a directory and return its inode
+ * @dir: The directory inode
+ * @dentry: The dentry of the new inode
+ * @nd: passed from Linux VFS, ignored by us
+ *
+ * Called by the VFS layer. Lock dir and call gfs2_lookupi()
+ *
+ * Returns: errno
+ */
+
+static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
+				  struct nameidata *nd)
+{
+	struct inode *inode = NULL;
+
+	dentry->d_op = &gfs2_dops;
+
+	inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
+	if (inode && IS_ERR(inode))
+		return ERR_PTR(PTR_ERR(inode));
+
+	if (inode)
+		return d_splice_alias(inode, dentry);
+	d_add(dentry, inode);
+
+	return NULL;
+}
+
+/**
+ * gfs2_link - Link to a file
+ * @old_dentry: The inode to link
+ * @dir: Add link to this directory
+ * @dentry: The name of the link
+ *
+ * Link the inode in "old_dentry" into the directory "dir" with the
+ * name in "dentry".
+ *
+ * Returns: errno
+ */
+
+static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
+		     struct dentry *dentry)
+{
+	struct gfs2_inode *dip = GFS2_I(dir);
+	struct gfs2_sbd *sdp = GFS2_SB(dir);
+	struct inode *inode = old_dentry->d_inode;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder ghs[2];
+	int alloc_required;
+	int error;
+
+	if (S_ISDIR(ip->i_di.di_mode))
+		return -EPERM;
+
+	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+
+	error = gfs2_glock_nq_m(2, ghs);
+	if (error)
+		goto out;
+
+	error = permission(dir, MAY_WRITE | MAY_EXEC, NULL);
+	if (error)
+		goto out_gunlock;
+
+	error = gfs2_dir_search(dir, &dentry->d_name, NULL, NULL);
+	switch (error) {
+	case -ENOENT:
+		break;
+	case 0:
+		error = -EEXIST;
+	default:
+		goto out_gunlock;
+	}
+
+	error = -EINVAL;
+	if (!dip->i_di.di_nlink)
+		goto out_gunlock;
+	error = -EFBIG;
+	if (dip->i_di.di_entries == (u32)-1)
+		goto out_gunlock;
+	error = -EPERM;
+	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+		goto out_gunlock;
+	error = -EINVAL;
+	if (!ip->i_di.di_nlink)
+		goto out_gunlock;
+	error = -EMLINK;
+	if (ip->i_di.di_nlink == (u32)-1)
+		goto out_gunlock;
+
+	alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);
+	if (error < 0)
+		goto out_gunlock;
+	error = 0;
+
+	if (alloc_required) {
+		struct gfs2_alloc *al = gfs2_alloc_get(dip);
+
+		error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+		if (error)
+			goto out_alloc;
+
+		error = gfs2_quota_check(dip, dip->i_di.di_uid,
+					 dip->i_di.di_gid);
+		if (error)
+			goto out_gunlock_q;
+
+		al->al_requested = sdp->sd_max_dirres;
+
+		error = gfs2_inplace_reserve(dip);
+		if (error)
+			goto out_gunlock_q;
+
+		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
+					 al->al_rgd->rd_ri.ri_length +
+					 2 * RES_DINODE + RES_STATFS +
+					 RES_QUOTA, 0);
+		if (error)
+			goto out_ipres;
+	} else {
+		error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
+		if (error)
+			goto out_ipres;
+	}
+
+	error = gfs2_dir_add(dir, &dentry->d_name, &ip->i_num,
+			     IF2DT(ip->i_di.di_mode));
+	if (error)
+		goto out_end_trans;
+
+	error = gfs2_change_nlink(ip, +1);
+
+out_end_trans:
+	gfs2_trans_end(sdp);
+out_ipres:
+	if (alloc_required)
+		gfs2_inplace_release(dip);
+out_gunlock_q:
+	if (alloc_required)
+		gfs2_quota_unlock(dip);
+out_alloc:
+	if (alloc_required)
+		gfs2_alloc_put(dip);
+out_gunlock:
+	gfs2_glock_dq_m(2, ghs);
+out:
+	gfs2_holder_uninit(ghs);
+	gfs2_holder_uninit(ghs + 1);
+	if (!error) {
+		atomic_inc(&inode->i_count);
+		d_instantiate(dentry, inode);
+		mark_inode_dirty(inode);
+	}
+	return error;
+}
+
+/**
+ * gfs2_unlink - Unlink a file
+ * @dir: The inode of the directory containing the file to unlink
+ * @dentry: The file itself
+ *
+ * Unlink a file.  Call gfs2_unlinki()
+ *
+ * Returns: errno
+ */
+
+static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
+{
+	struct gfs2_inode *dip = GFS2_I(dir);
+	struct gfs2_sbd *sdp = GFS2_SB(dir);
+	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+	struct gfs2_holder ghs[2];
+	int error;
+
+	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+
+	error = gfs2_glock_nq_m(2, ghs);
+	if (error)
+		goto out;
+
+	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
+	if (error)
+		goto out_gunlock;
+
+	error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
+	if (error)
+		goto out_gunlock;
+
+	error = gfs2_dir_del(dip, &dentry->d_name);
+        if (error)
+                goto out_end_trans;
+
+	error = gfs2_change_nlink(ip, -1);
+
+out_end_trans:
+	gfs2_trans_end(sdp);
+out_gunlock:
+	gfs2_glock_dq_m(2, ghs);
+out:
+	gfs2_holder_uninit(ghs);
+	gfs2_holder_uninit(ghs + 1);
+	return error;
+}
+
+/**
+ * gfs2_symlink - Create a symlink
+ * @dir: The directory to create the symlink in
+ * @dentry: The dentry to put the symlink in
+ * @symname: The thing which the link points to
+ *
+ * Returns: errno
+ */
+
+static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
+			const char *symname)
+{
+	struct gfs2_inode *dip = GFS2_I(dir), *ip;
+	struct gfs2_sbd *sdp = GFS2_SB(dir);
+	struct gfs2_holder ghs[2];
+	struct inode *inode;
+	struct buffer_head *dibh;
+	int size;
+	int error;
+
+	/* Must be stuffed with a null terminator for gfs2_follow_link() */
+	size = strlen(symname);
+	if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
+		return -ENAMETOOLONG;
+
+	gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+	inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO);
+	if (IS_ERR(inode)) {
+		gfs2_holder_uninit(ghs);
+		return PTR_ERR(inode);
+	}
+
+	ip = ghs[1].gh_gl->gl_object;
+
+	ip->i_di.di_size = size;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+
+	if (!gfs2_assert_withdraw(sdp, !error)) {
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname,
+		       size);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(sdp);
+	if (dip->i_alloc.al_rgd)
+		gfs2_inplace_release(dip);
+	gfs2_quota_unlock(dip);
+	gfs2_alloc_put(dip);
+
+	gfs2_glock_dq_uninit_m(2, ghs);
+
+	d_instantiate(dentry, inode);
+	mark_inode_dirty(inode);
+
+	return 0;
+}
+
+/**
+ * gfs2_mkdir - Make a directory
+ * @dir: The parent directory of the new one
+ * @dentry: The dentry of the new directory
+ * @mode: The mode of the new directory
+ *
+ * Returns: errno
+ */
+
+static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	struct gfs2_inode *dip = GFS2_I(dir), *ip;
+	struct gfs2_sbd *sdp = GFS2_SB(dir);
+	struct gfs2_holder ghs[2];
+	struct inode *inode;
+	struct buffer_head *dibh;
+	int error;
+
+	gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+	inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode);
+	if (IS_ERR(inode)) {
+		gfs2_holder_uninit(ghs);
+		return PTR_ERR(inode);
+	}
+
+	ip = ghs[1].gh_gl->gl_object;
+
+	ip->i_di.di_nlink = 2;
+	ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
+	ip->i_di.di_flags |= GFS2_DIF_JDATA;
+	ip->i_di.di_payload_format = GFS2_FORMAT_DE;
+	ip->i_di.di_entries = 2;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+
+	if (!gfs2_assert_withdraw(sdp, !error)) {
+		struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
+		struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
+		struct qstr str;
+
+		gfs2_str2qstr(&str, ".");
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);
+		dent->de_inum = di->di_num; /* already GFS2 endian */
+		dent->de_type = cpu_to_be16(DT_DIR);
+		di->di_entries = cpu_to_be32(1);
+
+		gfs2_str2qstr(&str, "..");
+		dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
+		gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
+
+		gfs2_inum_out(&dip->i_num, &dent->de_inum);
+		dent->de_type = cpu_to_be16(DT_DIR);
+
+		gfs2_dinode_out(&ip->i_di, di);
+
+		brelse(dibh);
+	}
+
+	error = gfs2_change_nlink(dip, +1);
+	gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
+
+	gfs2_trans_end(sdp);
+	if (dip->i_alloc.al_rgd)
+		gfs2_inplace_release(dip);
+	gfs2_quota_unlock(dip);
+	gfs2_alloc_put(dip);
+
+	gfs2_glock_dq_uninit_m(2, ghs);
+
+	d_instantiate(dentry, inode);
+	mark_inode_dirty(inode);
+
+	return 0;
+}
+
+/**
+ * gfs2_rmdir - Remove a directory
+ * @dir: The parent directory of the directory to be removed
+ * @dentry: The dentry of the directory to remove
+ *
+ * Remove a directory. Call gfs2_rmdiri()
+ *
+ * Returns: errno
+ */
+
+static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
+{
+	struct gfs2_inode *dip = GFS2_I(dir);
+	struct gfs2_sbd *sdp = GFS2_SB(dir);
+	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+	struct gfs2_holder ghs[2];
+	int error;
+
+	gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+
+	error = gfs2_glock_nq_m(2, ghs);
+	if (error)
+		goto out;
+
+	error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
+	if (error)
+		goto out_gunlock;
+
+	if (ip->i_di.di_entries < 2) {
+		if (gfs2_consist_inode(ip))
+			gfs2_dinode_print(&ip->i_di);
+		error = -EIO;
+		goto out_gunlock;
+	}
+	if (ip->i_di.di_entries > 2) {
+		error = -ENOTEMPTY;
+		goto out_gunlock;
+	}
+
+	error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0);
+	if (error)
+		goto out_gunlock;
+
+	error = gfs2_rmdiri(dip, &dentry->d_name, ip);
+
+	gfs2_trans_end(sdp);
+
+out_gunlock:
+	gfs2_glock_dq_m(2, ghs);
+out:
+	gfs2_holder_uninit(ghs);
+	gfs2_holder_uninit(ghs + 1);
+	return error;
+}
+
+/**
+ * gfs2_mknod - Make a special file
+ * @dir: The directory in which the special file will reside
+ * @dentry: The dentry of the special file
+ * @mode: The mode of the special file
+ * @rdev: The device specification of the special file
+ *
+ */
+
+static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
+		      dev_t dev)
+{
+	struct gfs2_inode *dip = GFS2_I(dir), *ip;
+	struct gfs2_sbd *sdp = GFS2_SB(dir);
+	struct gfs2_holder ghs[2];
+	struct inode *inode;
+	struct buffer_head *dibh;
+	u32 major = 0, minor = 0;
+	int error;
+
+	switch (mode & S_IFMT) {
+	case S_IFBLK:
+	case S_IFCHR:
+		major = MAJOR(dev);
+		minor = MINOR(dev);
+		break;
+	case S_IFIFO:
+	case S_IFSOCK:
+		break;
+	default:
+		return -EOPNOTSUPP;
+	};
+
+	gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+	inode = gfs2_createi(ghs, &dentry->d_name, mode);
+	if (IS_ERR(inode)) {
+		gfs2_holder_uninit(ghs);
+		return PTR_ERR(inode);
+	}
+
+	ip = ghs[1].gh_gl->gl_object;
+
+	ip->i_di.di_major = major;
+	ip->i_di.di_minor = minor;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+
+	if (!gfs2_assert_withdraw(sdp, !error)) {
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	gfs2_trans_end(sdp);
+	if (dip->i_alloc.al_rgd)
+		gfs2_inplace_release(dip);
+	gfs2_quota_unlock(dip);
+	gfs2_alloc_put(dip);
+
+	gfs2_glock_dq_uninit_m(2, ghs);
+
+	d_instantiate(dentry, inode);
+	mark_inode_dirty(inode);
+
+	return 0;
+}
+
+/**
+ * gfs2_rename - Rename a file
+ * @odir: Parent directory of old file name
+ * @odentry: The old dentry of the file
+ * @ndir: Parent directory of new file name
+ * @ndentry: The new dentry of the file
+ *
+ * Returns: errno
+ */
+
+static int gfs2_rename(struct inode *odir, struct dentry *odentry,
+		       struct inode *ndir, struct dentry *ndentry)
+{
+	struct gfs2_inode *odip = GFS2_I(odir);
+	struct gfs2_inode *ndip = GFS2_I(ndir);
+	struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
+	struct gfs2_inode *nip = NULL;
+	struct gfs2_sbd *sdp = GFS2_SB(odir);
+	struct gfs2_holder ghs[4], r_gh;
+	unsigned int num_gh;
+	int dir_rename = 0;
+	int alloc_required;
+	unsigned int x;
+	int error;
+
+	if (ndentry->d_inode) {
+		nip = GFS2_I(ndentry->d_inode);
+		if (ip == nip)
+			return 0;
+	}
+
+	/* Make sure we aren't trying to move a dirctory into it's subdir */
+
+	if (S_ISDIR(ip->i_di.di_mode) && odip != ndip) {
+		dir_rename = 1;
+
+		error = gfs2_glock_nq_init(sdp->sd_rename_gl,
+					   LM_ST_EXCLUSIVE, 0,
+					   &r_gh);
+		if (error)
+			goto out;
+
+		error = gfs2_ok_to_move(ip, ndip);
+		if (error)
+			goto out_gunlock_r;
+	}
+
+	num_gh = 1;
+	gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+	if (odip != ndip) {
+		gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+		num_gh++;
+	}
+	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+	num_gh++;
+
+	if (nip) {
+		gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+		num_gh++;
+	}
+
+	error = gfs2_glock_nq_m(num_gh, ghs);
+	if (error)
+		goto out_uninit;
+
+	/* Check out the old directory */
+
+	error = gfs2_unlink_ok(odip, &odentry->d_name, ip);
+	if (error)
+		goto out_gunlock;
+
+	/* Check out the new directory */
+
+	if (nip) {
+		error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip);
+		if (error)
+			goto out_gunlock;
+
+		if (S_ISDIR(nip->i_di.di_mode)) {
+			if (nip->i_di.di_entries < 2) {
+				if (gfs2_consist_inode(nip))
+					gfs2_dinode_print(&nip->i_di);
+				error = -EIO;
+				goto out_gunlock;
+			}
+			if (nip->i_di.di_entries > 2) {
+				error = -ENOTEMPTY;
+				goto out_gunlock;
+			}
+		}
+	} else {
+		error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL);
+		if (error)
+			goto out_gunlock;
+
+		error = gfs2_dir_search(ndir, &ndentry->d_name, NULL, NULL);
+		switch (error) {
+		case -ENOENT:
+			error = 0;
+			break;
+		case 0:
+			error = -EEXIST;
+		default:
+			goto out_gunlock;
+		};
+
+		if (odip != ndip) {
+			if (!ndip->i_di.di_nlink) {
+				error = -EINVAL;
+				goto out_gunlock;
+			}
+			if (ndip->i_di.di_entries == (u32)-1) {
+				error = -EFBIG;
+				goto out_gunlock;
+			}
+			if (S_ISDIR(ip->i_di.di_mode) &&
+			    ndip->i_di.di_nlink == (u32)-1) {
+				error = -EMLINK;
+				goto out_gunlock;
+			}
+		}
+	}
+
+	/* Check out the dir to be renamed */
+
+	if (dir_rename) {
+		error = permission(odentry->d_inode, MAY_WRITE, NULL);
+		if (error)
+			goto out_gunlock;
+	}
+
+	alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name);
+	if (error < 0)
+		goto out_gunlock;
+	error = 0;
+
+	if (alloc_required) {
+		struct gfs2_alloc *al = gfs2_alloc_get(ndip);
+
+		error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+		if (error)
+			goto out_alloc;
+
+		error = gfs2_quota_check(ndip, ndip->i_di.di_uid,
+					 ndip->i_di.di_gid);
+		if (error)
+			goto out_gunlock_q;
+
+		al->al_requested = sdp->sd_max_dirres;
+
+		error = gfs2_inplace_reserve(ndip);
+		if (error)
+			goto out_gunlock_q;
+
+		error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
+					 al->al_rgd->rd_ri.ri_length +
+					 4 * RES_DINODE + 4 * RES_LEAF +
+					 RES_STATFS + RES_QUOTA, 0);
+		if (error)
+			goto out_ipreserv;
+	} else {
+		error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
+					 5 * RES_LEAF, 0);
+		if (error)
+			goto out_gunlock;
+	}
+
+	/* Remove the target file, if it exists */
+
+	if (nip) {
+		if (S_ISDIR(nip->i_di.di_mode))
+			error = gfs2_rmdiri(ndip, &ndentry->d_name, nip);
+		else {
+			error = gfs2_dir_del(ndip, &ndentry->d_name);
+			if (error)
+				goto out_end_trans;
+			error = gfs2_change_nlink(nip, -1);
+		}
+		if (error)
+			goto out_end_trans;
+	}
+
+	if (dir_rename) {
+		struct qstr name;
+		gfs2_str2qstr(&name, "..");
+
+		error = gfs2_change_nlink(ndip, +1);
+		if (error)
+			goto out_end_trans;
+		error = gfs2_change_nlink(odip, -1);
+		if (error)
+			goto out_end_trans;
+
+		error = gfs2_dir_mvino(ip, &name, &ndip->i_num, DT_DIR);
+		if (error)
+			goto out_end_trans;
+	} else {
+		struct buffer_head *dibh;
+		error = gfs2_meta_inode_buffer(ip, &dibh);
+		if (error)
+			goto out_end_trans;
+		ip->i_di.di_ctime = get_seconds();
+		gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+		gfs2_dinode_out(&ip->i_di, dibh->b_data);
+		brelse(dibh);
+	}
+
+	error = gfs2_dir_del(odip, &odentry->d_name);
+	if (error)
+		goto out_end_trans;
+
+	error = gfs2_dir_add(ndir, &ndentry->d_name, &ip->i_num,
+			     IF2DT(ip->i_di.di_mode));
+	if (error)
+		goto out_end_trans;
+
+out_end_trans:
+	gfs2_trans_end(sdp);
+out_ipreserv:
+	if (alloc_required)
+		gfs2_inplace_release(ndip);
+out_gunlock_q:
+	if (alloc_required)
+		gfs2_quota_unlock(ndip);
+out_alloc:
+	if (alloc_required)
+		gfs2_alloc_put(ndip);
+out_gunlock:
+	gfs2_glock_dq_m(num_gh, ghs);
+out_uninit:
+	for (x = 0; x < num_gh; x++)
+		gfs2_holder_uninit(ghs + x);
+out_gunlock_r:
+	if (dir_rename)
+		gfs2_glock_dq_uninit(&r_gh);
+out:
+	return error;
+}
+
+/**
+ * gfs2_readlink - Read the value of a symlink
+ * @dentry: the symlink
+ * @buf: the buffer to read the symlink data into
+ * @size: the size of the buffer
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readlink(struct dentry *dentry, char __user *user_buf,
+			 int user_size)
+{
+	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+	char array[GFS2_FAST_NAME_SIZE], *buf = array;
+	unsigned int len = GFS2_FAST_NAME_SIZE;
+	int error;
+
+	error = gfs2_readlinki(ip, &buf, &len);
+	if (error)
+		return error;
+
+	if (user_size > len - 1)
+		user_size = len - 1;
+
+	if (copy_to_user(user_buf, buf, user_size))
+		error = -EFAULT;
+	else
+		error = user_size;
+
+	if (buf != array)
+		kfree(buf);
+
+	return error;
+}
+
+/**
+ * gfs2_follow_link - Follow a symbolic link
+ * @dentry: The dentry of the link
+ * @nd: Data that we pass to vfs_follow_link()
+ *
+ * This can handle symlinks of any size. It is optimised for symlinks
+ * under GFS2_FAST_NAME_SIZE.
+ *
+ * Returns: 0 on success or error code
+ */
+
+static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+	struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+	char array[GFS2_FAST_NAME_SIZE], *buf = array;
+	unsigned int len = GFS2_FAST_NAME_SIZE;
+	int error;
+
+	error = gfs2_readlinki(ip, &buf, &len);
+	if (!error) {
+		error = vfs_follow_link(nd, buf);
+		if (buf != array)
+			kfree(buf);
+	}
+
+	return ERR_PTR(error);
+}
+
+/**
+ * gfs2_permission -
+ * @inode:
+ * @mask:
+ * @nd: passed from Linux VFS, ignored by us
+ *
+ * Returns: errno
+ */
+
+static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder i_gh;
+	int error;
+
+	if (ip->i_vn == ip->i_gl->gl_vn)
+		return generic_permission(inode, mask, gfs2_check_acl);
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+	if (!error) {
+		error = generic_permission(inode, mask, gfs2_check_acl_locked);
+		gfs2_glock_dq_uninit(&i_gh);
+	}
+
+	return error;
+}
+
+static int setattr_size(struct inode *inode, struct iattr *attr)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	int error;
+
+	if (attr->ia_size != ip->i_di.di_size) {
+		error = vmtruncate(inode, attr->ia_size);
+		if (error)
+			return error;
+	}
+
+	error = gfs2_truncatei(ip, attr->ia_size);
+	if (error)
+		return error;
+
+	return error;
+}
+
+static int setattr_chown(struct inode *inode, struct iattr *attr)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct buffer_head *dibh;
+	u32 ouid, ogid, nuid, ngid;
+	int error;
+
+	ouid = ip->i_di.di_uid;
+	ogid = ip->i_di.di_gid;
+	nuid = attr->ia_uid;
+	ngid = attr->ia_gid;
+
+	if (!(attr->ia_valid & ATTR_UID) || ouid == nuid)
+		ouid = nuid = NO_QUOTA_CHANGE;
+	if (!(attr->ia_valid & ATTR_GID) || ogid == ngid)
+		ogid = ngid = NO_QUOTA_CHANGE;
+
+	gfs2_alloc_get(ip);
+
+	error = gfs2_quota_lock(ip, nuid, ngid);
+	if (error)
+		goto out_alloc;
+
+	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
+		error = gfs2_quota_check(ip, nuid, ngid);
+		if (error)
+			goto out_gunlock_q;
+	}
+
+	error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0);
+	if (error)
+		goto out_gunlock_q;
+
+	error = gfs2_meta_inode_buffer(ip, &dibh);
+	if (error)
+		goto out_end_trans;
+
+	error = inode_setattr(inode, attr);
+	gfs2_assert_warn(sdp, !error);
+	gfs2_inode_attr_out(ip);
+
+	gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+	gfs2_dinode_out(&ip->i_di, dibh->b_data);
+	brelse(dibh);
+
+	if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
+		gfs2_quota_change(ip, -ip->i_di.di_blocks, ouid, ogid);
+		gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid);
+	}
+
+out_end_trans:
+	gfs2_trans_end(sdp);
+out_gunlock_q:
+	gfs2_quota_unlock(ip);
+out_alloc:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
+/**
+ * gfs2_setattr - Change attributes on an inode
+ * @dentry: The dentry which is changing
+ * @attr: The structure describing the change
+ *
+ * The VFS layer wants to change one or more of an inodes attributes.  Write
+ * that change out to disk.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	struct inode *inode = dentry->d_inode;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder i_gh;
+	int error;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+	if (error)
+		return error;
+
+	error = -EPERM;
+	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+		goto out;
+
+	error = inode_change_ok(inode, attr);
+	if (error)
+		goto out;
+
+	if (attr->ia_valid & ATTR_SIZE)
+		error = setattr_size(inode, attr);
+	else if (attr->ia_valid & (ATTR_UID | ATTR_GID))
+		error = setattr_chown(inode, attr);
+	else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
+		error = gfs2_acl_chmod(ip, attr);
+	else
+		error = gfs2_setattr_simple(ip, attr);
+
+out:
+	gfs2_glock_dq_uninit(&i_gh);
+	if (!error)
+		mark_inode_dirty(inode);
+	return error;
+}
+
+/**
+ * gfs2_getattr - Read out an inode's attributes
+ * @mnt: The vfsmount the inode is being accessed from
+ * @dentry: The dentry to stat
+ * @stat: The inode's stats
+ *
+ * Returns: errno
+ */
+
+static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
+			struct kstat *stat)
+{
+	struct inode *inode = dentry->d_inode;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder gh;
+	int error;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
+	if (!error) {
+		generic_fillattr(inode, stat);
+		gfs2_glock_dq_uninit(&gh);
+	}
+
+	return error;
+}
+
+static int gfs2_setxattr(struct dentry *dentry, const char *name,
+			 const void *data, size_t size, int flags)
+{
+	struct inode *inode = dentry->d_inode;
+	struct gfs2_ea_request er;
+
+	memset(&er, 0, sizeof(struct gfs2_ea_request));
+	er.er_type = gfs2_ea_name2type(name, &er.er_name);
+	if (er.er_type == GFS2_EATYPE_UNUSED)
+		return -EOPNOTSUPP;
+	er.er_data = (char *)data;
+	er.er_name_len = strlen(er.er_name);
+	er.er_data_len = size;
+	er.er_flags = flags;
+
+	gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE));
+
+	return gfs2_ea_set(GFS2_I(inode), &er);
+}
+
+static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,
+			     void *data, size_t size)
+{
+	struct gfs2_ea_request er;
+
+	memset(&er, 0, sizeof(struct gfs2_ea_request));
+	er.er_type = gfs2_ea_name2type(name, &er.er_name);
+	if (er.er_type == GFS2_EATYPE_UNUSED)
+		return -EOPNOTSUPP;
+	er.er_data = data;
+	er.er_name_len = strlen(er.er_name);
+	er.er_data_len = size;
+
+	return gfs2_ea_get(GFS2_I(dentry->d_inode), &er);
+}
+
+static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+	struct gfs2_ea_request er;
+
+	memset(&er, 0, sizeof(struct gfs2_ea_request));
+	er.er_data = (size) ? buffer : NULL;
+	er.er_data_len = size;
+
+	return gfs2_ea_list(GFS2_I(dentry->d_inode), &er);
+}
+
+static int gfs2_removexattr(struct dentry *dentry, const char *name)
+{
+	struct gfs2_ea_request er;
+
+	memset(&er, 0, sizeof(struct gfs2_ea_request));
+	er.er_type = gfs2_ea_name2type(name, &er.er_name);
+	if (er.er_type == GFS2_EATYPE_UNUSED)
+		return -EOPNOTSUPP;
+	er.er_name_len = strlen(er.er_name);
+
+	return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er);
+}
+
+struct inode_operations gfs2_file_iops = {
+	.permission = gfs2_permission,
+	.setattr = gfs2_setattr,
+	.getattr = gfs2_getattr,
+	.setxattr = gfs2_setxattr,
+	.getxattr = gfs2_getxattr,
+	.listxattr = gfs2_listxattr,
+	.removexattr = gfs2_removexattr,
+};
+
+struct inode_operations gfs2_dev_iops = {
+	.permission = gfs2_permission,
+	.setattr = gfs2_setattr,
+	.getattr = gfs2_getattr,
+	.setxattr = gfs2_setxattr,
+	.getxattr = gfs2_getxattr,
+	.listxattr = gfs2_listxattr,
+	.removexattr = gfs2_removexattr,
+};
+
+struct inode_operations gfs2_dir_iops = {
+	.create = gfs2_create,
+	.lookup = gfs2_lookup,
+	.link = gfs2_link,
+	.unlink = gfs2_unlink,
+	.symlink = gfs2_symlink,
+	.mkdir = gfs2_mkdir,
+	.rmdir = gfs2_rmdir,
+	.mknod = gfs2_mknod,
+	.rename = gfs2_rename,
+	.permission = gfs2_permission,
+	.setattr = gfs2_setattr,
+	.getattr = gfs2_getattr,
+	.setxattr = gfs2_setxattr,
+	.getxattr = gfs2_getxattr,
+	.listxattr = gfs2_listxattr,
+	.removexattr = gfs2_removexattr,
+};
+
+struct inode_operations gfs2_symlink_iops = {
+	.readlink = gfs2_readlink,
+	.follow_link = gfs2_follow_link,
+	.permission = gfs2_permission,
+	.setattr = gfs2_setattr,
+	.getattr = gfs2_getattr,
+	.setxattr = gfs2_setxattr,
+	.getxattr = gfs2_getxattr,
+	.listxattr = gfs2_listxattr,
+	.removexattr = gfs2_removexattr,
+};
+
diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h
new file mode 100644
index 0000000..b15acb4
--- /dev/null
+++ b/fs/gfs2/ops_inode.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_INODE_DOT_H__
+#define __OPS_INODE_DOT_H__
+
+#include <linux/fs.h>
+
+extern struct inode_operations gfs2_file_iops;
+extern struct inode_operations gfs2_dir_iops;
+extern struct inode_operations gfs2_symlink_iops;
+extern struct inode_operations gfs2_dev_iops;
+
+#endif /* __OPS_INODE_DOT_H__ */
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
new file mode 100644
index 0000000..06f06f7
--- /dev/null
+++ b/fs/gfs2/ops_super.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/statfs.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "inode.h"
+#include "lm.h"
+#include "log.h"
+#include "mount.h"
+#include "ops_super.h"
+#include "quota.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "super.h"
+#include "sys.h"
+#include "util.h"
+#include "trans.h"
+#include "dir.h"
+#include "eattr.h"
+#include "bmap.h"
+
+/**
+ * gfs2_write_inode - Make sure the inode is stable on the disk
+ * @inode: The inode
+ * @sync: synchronous write flag
+ *
+ * Returns: errno
+ */
+
+static int gfs2_write_inode(struct inode *inode, int sync)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+
+	/* Check this is a "normal" inode */
+	if (inode->i_private) {
+		if (current->flags & PF_MEMALLOC)
+			return 0;
+		if (sync)
+			gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_put_super - Unmount the filesystem
+ * @sb: The VFS superblock
+ *
+ */
+
+static void gfs2_put_super(struct super_block *sb)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	int error;
+
+	if (!sdp)
+		return;
+
+	if (!strncmp(sb->s_type->name, "gfs2meta", 8))
+		return; /* Nothing to do */
+
+	/*  Unfreeze the filesystem, if we need to  */
+
+	mutex_lock(&sdp->sd_freeze_lock);
+	if (sdp->sd_freeze_count)
+		gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
+	mutex_unlock(&sdp->sd_freeze_lock);
+
+	kthread_stop(sdp->sd_quotad_process);
+	kthread_stop(sdp->sd_logd_process);
+	kthread_stop(sdp->sd_recoverd_process);
+	while (sdp->sd_glockd_num--)
+		kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
+	kthread_stop(sdp->sd_scand_process);
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		error = gfs2_make_fs_ro(sdp);
+		if (error)
+			gfs2_io_error(sdp);
+	}
+	/*  At this point, we're through modifying the disk  */
+
+	/*  Release stuff  */
+
+	iput(sdp->sd_master_dir);
+	iput(sdp->sd_jindex);
+	iput(sdp->sd_inum_inode);
+	iput(sdp->sd_statfs_inode);
+	iput(sdp->sd_rindex);
+	iput(sdp->sd_quota_inode);
+
+	gfs2_glock_put(sdp->sd_rename_gl);
+	gfs2_glock_put(sdp->sd_trans_gl);
+
+	if (!sdp->sd_args.ar_spectator) {
+		gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
+		gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
+		gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
+		gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
+		gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
+		iput(sdp->sd_ir_inode);
+		iput(sdp->sd_sc_inode);
+		iput(sdp->sd_qc_inode);
+	}
+
+	gfs2_glock_dq_uninit(&sdp->sd_live_gh);
+	gfs2_clear_rgrpd(sdp);
+	gfs2_jindex_free(sdp);
+	/*  Take apart glock structures and buffer lists  */
+	gfs2_gl_hash_clear(sdp, WAIT);
+	/*  Unmount the locking protocol  */
+	gfs2_lm_unmount(sdp);
+
+	/*  At this point, we're through participating in the lockspace  */
+	gfs2_sys_fs_del(sdp);
+	kfree(sdp);
+}
+
+/**
+ * gfs2_write_super - disk commit all incore transactions
+ * @sb: the filesystem
+ *
+ * This function is called every time sync(2) is called.
+ * After this exits, all dirty buffers are synced.
+ */
+
+static void gfs2_write_super(struct super_block *sb)
+{
+	gfs2_log_flush(sb->s_fs_info, NULL);
+}
+
+/**
+ * gfs2_write_super_lockfs - prevent further writes to the filesystem
+ * @sb: the VFS structure for the filesystem
+ *
+ */
+
+static void gfs2_write_super_lockfs(struct super_block *sb)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	int error;
+
+	for (;;) {
+		error = gfs2_freeze_fs(sdp);
+		if (!error)
+			break;
+
+		switch (error) {
+		case -EBUSY:
+			fs_err(sdp, "waiting for recovery before freeze\n");
+			break;
+
+		default:
+			fs_err(sdp, "error freezing FS: %d\n", error);
+			break;
+		}
+
+		fs_err(sdp, "retrying...\n");
+		msleep(1000);
+	}
+}
+
+/**
+ * gfs2_unlockfs - reallow writes to the filesystem
+ * @sb: the VFS structure for the filesystem
+ *
+ */
+
+static void gfs2_unlockfs(struct super_block *sb)
+{
+	gfs2_unfreeze_fs(sb->s_fs_info);
+}
+
+/**
+ * gfs2_statfs - Gather and return stats about the filesystem
+ * @sb: The superblock
+ * @statfsbuf: The buffer
+ *
+ * Returns: 0 on success or error code
+ */
+
+static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	struct super_block *sb = dentry->d_inode->i_sb;
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	struct gfs2_statfs_change sc;
+	int error;
+
+	if (gfs2_tune_get(sdp, gt_statfs_slow))
+		error = gfs2_statfs_slow(sdp, &sc);
+	else
+		error = gfs2_statfs_i(sdp, &sc);
+
+	if (error)
+		return error;
+
+	buf->f_type = GFS2_MAGIC;
+	buf->f_bsize = sdp->sd_sb.sb_bsize;
+	buf->f_blocks = sc.sc_total;
+	buf->f_bfree = sc.sc_free;
+	buf->f_bavail = sc.sc_free;
+	buf->f_files = sc.sc_dinodes + sc.sc_free;
+	buf->f_ffree = sc.sc_free;
+	buf->f_namelen = GFS2_FNAMESIZE;
+
+	return 0;
+}
+
+/**
+ * gfs2_remount_fs - called when the FS is remounted
+ * @sb:  the filesystem
+ * @flags:  the remount flags
+ * @data:  extra data passed in (not used right now)
+ *
+ * Returns: errno
+ */
+
+static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	int error;
+
+	error = gfs2_mount_args(sdp, data, 1);
+	if (error)
+		return error;
+
+	if (sdp->sd_args.ar_spectator)
+		*flags |= MS_RDONLY;
+	else {
+		if (*flags & MS_RDONLY) {
+			if (!(sb->s_flags & MS_RDONLY))
+				error = gfs2_make_fs_ro(sdp);
+		} else if (!(*flags & MS_RDONLY) &&
+			   (sb->s_flags & MS_RDONLY)) {
+			error = gfs2_make_fs_rw(sdp);
+		}
+	}
+
+	if (*flags & (MS_NOATIME | MS_NODIRATIME))
+		set_bit(SDF_NOATIME, &sdp->sd_flags);
+	else
+		clear_bit(SDF_NOATIME, &sdp->sd_flags);
+
+	/* Don't let the VFS update atimes.  GFS2 handles this itself. */
+	*flags |= MS_NOATIME | MS_NODIRATIME;
+
+	return error;
+}
+
+/**
+ * gfs2_clear_inode - Deallocate an inode when VFS is done with it
+ * @inode: The VFS inode
+ *
+ */
+
+static void gfs2_clear_inode(struct inode *inode)
+{
+	/* This tells us its a "real" inode and not one which only
+	 * serves to contain an address space (see rgrp.c, meta_io.c)
+	 * which therefore doesn't have its own glocks.
+	 */
+	if (inode->i_private) {
+		struct gfs2_inode *ip = GFS2_I(inode);
+		gfs2_glock_inode_squish(inode);
+		gfs2_assert(inode->i_sb->s_fs_info, ip->i_gl->gl_state == LM_ST_UNLOCKED);
+		ip->i_gl->gl_object = NULL;
+		gfs2_glock_schedule_for_reclaim(ip->i_gl);
+		gfs2_glock_put(ip->i_gl);
+		ip->i_gl = NULL;
+		if (ip->i_iopen_gh.gh_gl)
+			gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+	}
+}
+
+/**
+ * gfs2_show_options - Show mount options for /proc/mounts
+ * @s: seq_file structure
+ * @mnt: vfsmount
+ *
+ * Returns: 0 on success or error code
+ */
+
+static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
+{
+	struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
+	struct gfs2_args *args = &sdp->sd_args;
+
+	if (args->ar_lockproto[0])
+		seq_printf(s, ",lockproto=%s", args->ar_lockproto);
+	if (args->ar_locktable[0])
+		seq_printf(s, ",locktable=%s", args->ar_locktable);
+	if (args->ar_hostdata[0])
+		seq_printf(s, ",hostdata=%s", args->ar_hostdata);
+	if (args->ar_spectator)
+		seq_printf(s, ",spectator");
+	if (args->ar_ignore_local_fs)
+		seq_printf(s, ",ignore_local_fs");
+	if (args->ar_localflocks)
+		seq_printf(s, ",localflocks");
+	if (args->ar_localcaching)
+		seq_printf(s, ",localcaching");
+	if (args->ar_debug)
+		seq_printf(s, ",debug");
+	if (args->ar_upgrade)
+		seq_printf(s, ",upgrade");
+	if (args->ar_num_glockd != GFS2_GLOCKD_DEFAULT)
+		seq_printf(s, ",num_glockd=%u", args->ar_num_glockd);
+	if (args->ar_posix_acl)
+		seq_printf(s, ",acl");
+	if (args->ar_quota != GFS2_QUOTA_DEFAULT) {
+		char *state;
+		switch (args->ar_quota) {
+		case GFS2_QUOTA_OFF:
+			state = "off";
+			break;
+		case GFS2_QUOTA_ACCOUNT:
+			state = "account";
+			break;
+		case GFS2_QUOTA_ON:
+			state = "on";
+			break;
+		default:
+			state = "unknown";
+			break;
+		}
+		seq_printf(s, ",quota=%s", state);
+	}
+	if (args->ar_suiddir)
+		seq_printf(s, ",suiddir");
+	if (args->ar_data != GFS2_DATA_DEFAULT) {
+		char *state;
+		switch (args->ar_data) {
+		case GFS2_DATA_WRITEBACK:
+			state = "writeback";
+			break;
+		case GFS2_DATA_ORDERED:
+			state = "ordered";
+			break;
+		default:
+			state = "unknown";
+			break;
+		}
+		seq_printf(s, ",data=%s", state);
+	}
+
+	return 0;
+}
+
+/*
+ * We have to (at the moment) hold the inodes main lock to cover
+ * the gap between unlocking the shared lock on the iopen lock and
+ * taking the exclusive lock. I'd rather do a shared -> exclusive
+ * conversion on the iopen lock, but we can change that later. This
+ * is safe, just less efficient.
+ */
+static void gfs2_delete_inode(struct inode *inode)
+{
+	struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_holder gh;
+	int error;
+
+	if (!inode->i_private)
+		goto out;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &gh);
+	if (unlikely(error)) {
+		gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+		goto out;
+	}
+
+	gfs2_glock_dq(&ip->i_iopen_gh);
+	gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
+	error = gfs2_glock_nq(&ip->i_iopen_gh);
+	if (error)
+		goto out_uninit;
+
+	if (S_ISDIR(ip->i_di.di_mode) &&
+	    (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
+		error = gfs2_dir_exhash_dealloc(ip);
+		if (error)
+			goto out_unlock;
+	}
+
+	if (ip->i_di.di_eattr) {
+		error = gfs2_ea_dealloc(ip);
+		if (error)
+			goto out_unlock;
+	}
+
+	if (!gfs2_is_stuffed(ip)) {
+		error = gfs2_file_dealloc(ip);
+		if (error)
+			goto out_unlock;
+	}
+
+	error = gfs2_dinode_dealloc(ip);
+
+out_unlock:
+	gfs2_glock_dq(&ip->i_iopen_gh);
+out_uninit:
+	gfs2_holder_uninit(&ip->i_iopen_gh);
+	gfs2_glock_dq_uninit(&gh);
+	if (error)
+		fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
+out:
+	truncate_inode_pages(&inode->i_data, 0);
+	clear_inode(inode);
+}
+
+
+
+static struct inode *gfs2_alloc_inode(struct super_block *sb)
+{
+	struct gfs2_sbd *sdp = sb->s_fs_info;
+	struct gfs2_inode *ip;
+
+	ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL);
+	if (ip) {
+		ip->i_flags = 0;
+		ip->i_gl = NULL;
+		ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default);
+		ip->i_last_pfault = jiffies;
+	}
+	return &ip->i_inode;
+}
+
+static void gfs2_destroy_inode(struct inode *inode)
+{
+	kmem_cache_free(gfs2_inode_cachep, inode);
+}
+
+struct super_operations gfs2_super_ops = {
+	.alloc_inode = gfs2_alloc_inode,
+	.destroy_inode = gfs2_destroy_inode,
+	.write_inode = gfs2_write_inode,
+	.delete_inode = gfs2_delete_inode,
+	.put_super = gfs2_put_super,
+	.write_super = gfs2_write_super,
+	.write_super_lockfs = gfs2_write_super_lockfs,
+	.unlockfs = gfs2_unlockfs,
+	.statfs = gfs2_statfs,
+	.remount_fs = gfs2_remount_fs,
+	.clear_inode = gfs2_clear_inode,
+	.show_options = gfs2_show_options,
+};
+
diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h
new file mode 100644
index 0000000..9de73f0
--- /dev/null
+++ b/fs/gfs2/ops_super.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_SUPER_DOT_H__
+#define __OPS_SUPER_DOT_H__
+
+#include <linux/fs.h>
+
+extern struct super_operations gfs2_super_ops;
+
+#endif /* __OPS_SUPER_DOT_H__ */
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
new file mode 100644
index 0000000..5453d29
--- /dev/null
+++ b/fs/gfs2/ops_vm.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "inode.h"
+#include "ops_vm.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+static void pfault_be_greedy(struct gfs2_inode *ip)
+{
+	unsigned int time;
+
+	spin_lock(&ip->i_spin);
+	time = ip->i_greedy;
+	ip->i_last_pfault = jiffies;
+	spin_unlock(&ip->i_spin);
+
+	igrab(&ip->i_inode);
+	if (gfs2_glock_be_greedy(ip->i_gl, time))
+		iput(&ip->i_inode);
+}
+
+static struct page *gfs2_private_nopage(struct vm_area_struct *area,
+					unsigned long address, int *type)
+{
+	struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
+	struct page *result;
+
+	set_bit(GIF_PAGED, &ip->i_flags);
+
+	result = filemap_nopage(area, address, type);
+
+	if (result && result != NOPAGE_OOM)
+		pfault_be_greedy(ip);
+
+	return result;
+}
+
+static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	unsigned long index = page->index;
+	u64 lblock = index << (PAGE_CACHE_SHIFT -
+				    sdp->sd_sb.sb_bsize_shift);
+	unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
+	struct gfs2_alloc *al;
+	unsigned int data_blocks, ind_blocks;
+	unsigned int x;
+	int error;
+
+	al = gfs2_alloc_get(ip);
+
+	error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+	if (error)
+		goto out;
+
+	error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+	if (error)
+		goto out_gunlock_q;
+
+	gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
+
+	al->al_requested = data_blocks + ind_blocks;
+
+	error = gfs2_inplace_reserve(ip);
+	if (error)
+		goto out_gunlock_q;
+
+	error = gfs2_trans_begin(sdp, al->al_rgd->rd_ri.ri_length +
+				 ind_blocks + RES_DINODE +
+				 RES_STATFS + RES_QUOTA, 0);
+	if (error)
+		goto out_ipres;
+
+	if (gfs2_is_stuffed(ip)) {
+		error = gfs2_unstuff_dinode(ip, NULL);
+		if (error)
+			goto out_trans;
+	}
+
+	for (x = 0; x < blocks; ) {
+		u64 dblock;
+		unsigned int extlen;
+		int new = 1;
+
+		error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
+		if (error)
+			goto out_trans;
+
+		lblock += extlen;
+		x += extlen;
+	}
+
+	gfs2_assert_warn(sdp, al->al_alloced);
+
+out_trans:
+	gfs2_trans_end(sdp);
+out_ipres:
+	gfs2_inplace_release(ip);
+out_gunlock_q:
+	gfs2_quota_unlock(ip);
+out:
+	gfs2_alloc_put(ip);
+	return error;
+}
+
+static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
+					   unsigned long address, int *type)
+{
+	struct file *file = area->vm_file;
+	struct gfs2_file *gf = file->private_data;
+	struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+	struct gfs2_holder i_gh;
+	struct page *result = NULL;
+	unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) +
+			      area->vm_pgoff;
+	int alloc_required;
+	int error;
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+	if (error)
+		return NULL;
+
+	set_bit(GIF_PAGED, &ip->i_flags);
+	set_bit(GIF_SW_PAGED, &ip->i_flags);
+
+	error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT,
+					  PAGE_CACHE_SIZE, &alloc_required);
+	if (error)
+		goto out;
+
+	set_bit(GFF_EXLOCK, &gf->f_flags);
+	result = filemap_nopage(area, address, type);
+	clear_bit(GFF_EXLOCK, &gf->f_flags);
+	if (!result || result == NOPAGE_OOM)
+		goto out;
+
+	if (alloc_required) {
+		error = alloc_page_backing(ip, result);
+		if (error) {
+			page_cache_release(result);
+			result = NULL;
+			goto out;
+		}
+		set_page_dirty(result);
+	}
+
+	pfault_be_greedy(ip);
+out:
+	gfs2_glock_dq_uninit(&i_gh);
+
+	return result;
+}
+
+struct vm_operations_struct gfs2_vm_ops_private = {
+	.nopage = gfs2_private_nopage,
+};
+
+struct vm_operations_struct gfs2_vm_ops_sharewrite = {
+	.nopage = gfs2_sharewrite_nopage,
+};
+
diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h
new file mode 100644
index 0000000..4ae8f43
--- /dev/null
+++ b/fs/gfs2/ops_vm.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_VM_DOT_H__
+#define __OPS_VM_DOT_H__
+
+#include <linux/mm.h>
+
+extern struct vm_operations_struct gfs2_vm_ops_private;
+extern struct vm_operations_struct gfs2_vm_ops_sharewrite;
+
+#endif /* __OPS_VM_DOT_H__ */
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
new file mode 100644
index 0000000..c69b94a
--- /dev/null
+++ b/fs/gfs2/quota.c
@@ -0,0 +1,1227 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+/*
+ * Quota change tags are associated with each transaction that allocates or
+ * deallocates space.  Those changes are accumulated locally to each node (in a
+ * per-node file) and then are periodically synced to the quota file.  This
+ * avoids the bottleneck of constantly touching the quota file, but introduces
+ * fuzziness in the current usage value of IDs that are being used on different
+ * nodes in the cluster simultaneously.  So, it is possible for a user on
+ * multiple nodes to overrun their quota, but that overrun is controlable.
+ * Since quota tags are part of transactions, there is no need to a quota check
+ * program to be run on node crashes or anything like that.
+ *
+ * There are couple of knobs that let the administrator manage the quota
+ * fuzziness.  "quota_quantum" sets the maximum time a quota change can be
+ * sitting on one node before being synced to the quota file.  (The default is
+ * 60 seconds.)  Another knob, "quota_scale" controls how quickly the frequency
+ * of quota file syncs increases as the user moves closer to their limit.  The
+ * more frequent the syncs, the more accurate the quota enforcement, but that
+ * means that there is more contention between the nodes for the quota file.
+ * The default value is one.  This sets the maximum theoretical quota overrun
+ * (with infinite node with infinite bandwidth) to twice the user's limit.  (In
+ * practice, the maximum overrun you see should be much less.)  A "quota_scale"
+ * number greater than one makes quota syncs more frequent and reduces the
+ * maximum overrun.  Numbers less than one (but greater than zero) make quota
+ * syncs less frequent.
+ *
+ * GFS quotas also use per-ID Lock Value Blocks (LVBs) to cache the contents of
+ * the quota file, so it is not being constantly read.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/sort.h>
+#include <linux/fs.h>
+#include <linux/bio.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "glops.h"
+#include "log.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "super.h"
+#include "trans.h"
+#include "inode.h"
+#include "ops_file.h"
+#include "ops_address.h"
+#include "util.h"
+
+#define QUOTA_USER 1
+#define QUOTA_GROUP 0
+
+static u64 qd2offset(struct gfs2_quota_data *qd)
+{
+	u64 offset;
+
+	offset = 2 * (u64)qd->qd_id + !test_bit(QDF_USER, &qd->qd_flags);
+	offset *= sizeof(struct gfs2_quota);
+
+	return offset;
+}
+
+static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id,
+		    struct gfs2_quota_data **qdp)
+{
+	struct gfs2_quota_data *qd;
+	int error;
+
+	qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_KERNEL);
+	if (!qd)
+		return -ENOMEM;
+
+	qd->qd_count = 1;
+	qd->qd_id = id;
+	if (user)
+		set_bit(QDF_USER, &qd->qd_flags);
+	qd->qd_slot = -1;
+
+	error = gfs2_glock_get(sdp, 2 * (u64)id + !user,
+			      &gfs2_quota_glops, CREATE, &qd->qd_gl);
+	if (error)
+		goto fail;
+
+	error = gfs2_lvb_hold(qd->qd_gl);
+	gfs2_glock_put(qd->qd_gl);
+	if (error)
+		goto fail;
+
+	*qdp = qd;
+
+	return 0;
+
+fail:
+	kfree(qd);
+	return error;
+}
+
+static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
+		  struct gfs2_quota_data **qdp)
+{
+	struct gfs2_quota_data *qd = NULL, *new_qd = NULL;
+	int error, found;
+
+	*qdp = NULL;
+
+	for (;;) {
+		found = 0;
+		spin_lock(&sdp->sd_quota_spin);
+		list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
+			if (qd->qd_id == id &&
+			    !test_bit(QDF_USER, &qd->qd_flags) == !user) {
+				qd->qd_count++;
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found)
+			qd = NULL;
+
+		if (!qd && new_qd) {
+			qd = new_qd;
+			list_add(&qd->qd_list, &sdp->sd_quota_list);
+			atomic_inc(&sdp->sd_quota_count);
+			new_qd = NULL;
+		}
+
+		spin_unlock(&sdp->sd_quota_spin);
+
+		if (qd || !create) {
+			if (new_qd) {
+				gfs2_lvb_unhold(new_qd->qd_gl);
+				kfree(new_qd);
+			}
+			*qdp = qd;
+			return 0;
+		}
+
+		error = qd_alloc(sdp, user, id, &new_qd);
+		if (error)
+			return error;
+	}
+}
+
+static void qd_hold(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+	spin_lock(&sdp->sd_quota_spin);
+	gfs2_assert(sdp, qd->qd_count);
+	qd->qd_count++;
+	spin_unlock(&sdp->sd_quota_spin);
+}
+
+static void qd_put(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+	spin_lock(&sdp->sd_quota_spin);
+	gfs2_assert(sdp, qd->qd_count);
+	if (!--qd->qd_count)
+		qd->qd_last_touched = jiffies;
+	spin_unlock(&sdp->sd_quota_spin);
+}
+
+static int slot_get(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+	unsigned int c, o = 0, b;
+	unsigned char byte = 0;
+
+	spin_lock(&sdp->sd_quota_spin);
+
+	if (qd->qd_slot_count++) {
+		spin_unlock(&sdp->sd_quota_spin);
+		return 0;
+	}
+
+	for (c = 0; c < sdp->sd_quota_chunks; c++)
+		for (o = 0; o < PAGE_SIZE; o++) {
+			byte = sdp->sd_quota_bitmap[c][o];
+			if (byte != 0xFF)
+				goto found;
+		}
+
+	goto fail;
+
+found:
+	for (b = 0; b < 8; b++)
+		if (!(byte & (1 << b)))
+			break;
+	qd->qd_slot = c * (8 * PAGE_SIZE) + o * 8 + b;
+
+	if (qd->qd_slot >= sdp->sd_quota_slots)
+		goto fail;
+
+	sdp->sd_quota_bitmap[c][o] |= 1 << b;
+
+	spin_unlock(&sdp->sd_quota_spin);
+
+	return 0;
+
+fail:
+	qd->qd_slot_count--;
+	spin_unlock(&sdp->sd_quota_spin);
+	return -ENOSPC;
+}
+
+static void slot_hold(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+	spin_lock(&sdp->sd_quota_spin);
+	gfs2_assert(sdp, qd->qd_slot_count);
+	qd->qd_slot_count++;
+	spin_unlock(&sdp->sd_quota_spin);
+}
+
+static void slot_put(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+	spin_lock(&sdp->sd_quota_spin);
+	gfs2_assert(sdp, qd->qd_slot_count);
+	if (!--qd->qd_slot_count) {
+		gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, qd->qd_slot, 0);
+		qd->qd_slot = -1;
+	}
+	spin_unlock(&sdp->sd_quota_spin);
+}
+
+static int bh_get(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
+	unsigned int block, offset;
+	struct buffer_head *bh;
+	int error;
+	struct buffer_head bh_map;
+
+	mutex_lock(&sdp->sd_quota_mutex);
+
+	if (qd->qd_bh_count++) {
+		mutex_unlock(&sdp->sd_quota_mutex);
+		return 0;
+	}
+
+	block = qd->qd_slot / sdp->sd_qc_per_block;
+	offset = qd->qd_slot % sdp->sd_qc_per_block;;
+
+	error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map, 1);
+	if (error)
+		goto fail;
+	error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh);
+	if (error)
+		goto fail;
+	error = -EIO;
+	if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC))
+		goto fail_brelse;
+
+	qd->qd_bh = bh;
+	qd->qd_bh_qc = (struct gfs2_quota_change *)
+		(bh->b_data + sizeof(struct gfs2_meta_header) +
+		 offset * sizeof(struct gfs2_quota_change));
+
+	mutex_lock(&sdp->sd_quota_mutex);
+
+	return 0;
+
+fail_brelse:
+	brelse(bh);
+fail:
+	qd->qd_bh_count--;
+	mutex_unlock(&sdp->sd_quota_mutex);
+	return error;
+}
+
+static void bh_put(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+	mutex_lock(&sdp->sd_quota_mutex);
+	gfs2_assert(sdp, qd->qd_bh_count);
+	if (!--qd->qd_bh_count) {
+		brelse(qd->qd_bh);
+		qd->qd_bh = NULL;
+		qd->qd_bh_qc = NULL;
+	}
+	mutex_unlock(&sdp->sd_quota_mutex);
+}
+
+static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
+{
+	struct gfs2_quota_data *qd = NULL;
+	int error;
+	int found = 0;
+
+	*qdp = NULL;
+
+	if (sdp->sd_vfs->s_flags & MS_RDONLY)
+		return 0;
+
+	spin_lock(&sdp->sd_quota_spin);
+
+	list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
+		if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
+		    !test_bit(QDF_CHANGE, &qd->qd_flags) ||
+		    qd->qd_sync_gen >= sdp->sd_quota_sync_gen)
+			continue;
+
+		list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
+
+		set_bit(QDF_LOCKED, &qd->qd_flags);
+		gfs2_assert_warn(sdp, qd->qd_count);
+		qd->qd_count++;
+		qd->qd_change_sync = qd->qd_change;
+		gfs2_assert_warn(sdp, qd->qd_slot_count);
+		qd->qd_slot_count++;
+		found = 1;
+
+		break;
+	}
+
+	if (!found)
+		qd = NULL;
+
+	spin_unlock(&sdp->sd_quota_spin);
+
+	if (qd) {
+		gfs2_assert_warn(sdp, qd->qd_change_sync);
+		error = bh_get(qd);
+		if (error) {
+			clear_bit(QDF_LOCKED, &qd->qd_flags);
+			slot_put(qd);
+			qd_put(qd);
+			return error;
+		}
+	}
+
+	*qdp = qd;
+
+	return 0;
+}
+
+static int qd_trylock(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+	if (sdp->sd_vfs->s_flags & MS_RDONLY)
+		return 0;
+
+	spin_lock(&sdp->sd_quota_spin);
+
+	if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
+	    !test_bit(QDF_CHANGE, &qd->qd_flags)) {
+		spin_unlock(&sdp->sd_quota_spin);
+		return 0;
+	}
+
+	list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
+
+	set_bit(QDF_LOCKED, &qd->qd_flags);
+	gfs2_assert_warn(sdp, qd->qd_count);
+	qd->qd_count++;
+	qd->qd_change_sync = qd->qd_change;
+	gfs2_assert_warn(sdp, qd->qd_slot_count);
+	qd->qd_slot_count++;
+
+	spin_unlock(&sdp->sd_quota_spin);
+
+	gfs2_assert_warn(sdp, qd->qd_change_sync);
+	if (bh_get(qd)) {
+		clear_bit(QDF_LOCKED, &qd->qd_flags);
+		slot_put(qd);
+		qd_put(qd);
+		return 0;
+	}
+
+	return 1;
+}
+
+static void qd_unlock(struct gfs2_quota_data *qd)
+{
+	gfs2_assert_warn(qd->qd_gl->gl_sbd,
+			 test_bit(QDF_LOCKED, &qd->qd_flags));
+	clear_bit(QDF_LOCKED, &qd->qd_flags);
+	bh_put(qd);
+	slot_put(qd);
+	qd_put(qd);
+}
+
+static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
+		    struct gfs2_quota_data **qdp)
+{
+	int error;
+
+	error = qd_get(sdp, user, id, create, qdp);
+	if (error)
+		return error;
+
+	error = slot_get(*qdp);
+	if (error)
+		goto fail;
+
+	error = bh_get(*qdp);
+	if (error)
+		goto fail_slot;
+
+	return 0;
+
+fail_slot:
+	slot_put(*qdp);
+fail:
+	qd_put(*qdp);
+	return error;
+}
+
+static void qdsb_put(struct gfs2_quota_data *qd)
+{
+	bh_put(qd);
+	slot_put(qd);
+	qd_put(qd);
+}
+
+int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_quota_data **qd = al->al_qd;
+	int error;
+
+	if (gfs2_assert_warn(sdp, !al->al_qd_num) ||
+	    gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)))
+		return -EIO;
+
+	if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
+		return 0;
+
+	error = qdsb_get(sdp, QUOTA_USER, ip->i_di.di_uid, CREATE, qd);
+	if (error)
+		goto out;
+	al->al_qd_num++;
+	qd++;
+
+	error = qdsb_get(sdp, QUOTA_GROUP, ip->i_di.di_gid, CREATE, qd);
+	if (error)
+		goto out;
+	al->al_qd_num++;
+	qd++;
+
+	if (uid != NO_QUOTA_CHANGE && uid != ip->i_di.di_uid) {
+		error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd);
+		if (error)
+			goto out;
+		al->al_qd_num++;
+		qd++;
+	}
+
+	if (gid != NO_QUOTA_CHANGE && gid != ip->i_di.di_gid) {
+		error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd);
+		if (error)
+			goto out;
+		al->al_qd_num++;
+		qd++;
+	}
+
+out:
+	if (error)
+		gfs2_quota_unhold(ip);
+	return error;
+}
+
+void gfs2_quota_unhold(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	unsigned int x;
+
+	gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
+
+	for (x = 0; x < al->al_qd_num; x++) {
+		qdsb_put(al->al_qd[x]);
+		al->al_qd[x] = NULL;
+	}
+	al->al_qd_num = 0;
+}
+
+static int sort_qd(const void *a, const void *b)
+{
+	const struct gfs2_quota_data *qd_a = *(const struct gfs2_quota_data **)a;
+	const struct gfs2_quota_data *qd_b = *(const struct gfs2_quota_data **)b;
+
+	if (!test_bit(QDF_USER, &qd_a->qd_flags) !=
+	    !test_bit(QDF_USER, &qd_b->qd_flags)) {
+		if (test_bit(QDF_USER, &qd_a->qd_flags))
+			return -1;
+		else
+			return 1;
+	}
+	if (qd_a->qd_id < qd_b->qd_id)
+		return -1;
+	if (qd_a->qd_id > qd_b->qd_id)
+		return 1;
+
+	return 0;
+}
+
+static void do_qc(struct gfs2_quota_data *qd, s64 change)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
+	struct gfs2_quota_change *qc = qd->qd_bh_qc;
+	s64 x;
+
+	mutex_lock(&sdp->sd_quota_mutex);
+	gfs2_trans_add_bh(ip->i_gl, qd->qd_bh, 1);
+
+	if (!test_bit(QDF_CHANGE, &qd->qd_flags)) {
+		qc->qc_change = 0;
+		qc->qc_flags = 0;
+		if (test_bit(QDF_USER, &qd->qd_flags))
+			qc->qc_flags = cpu_to_be32(GFS2_QCF_USER);
+		qc->qc_id = cpu_to_be32(qd->qd_id);
+	}
+
+	x = qc->qc_change;
+	x = be64_to_cpu(x) + change;
+	qc->qc_change = cpu_to_be64(x);
+
+	spin_lock(&sdp->sd_quota_spin);
+	qd->qd_change = x;
+	spin_unlock(&sdp->sd_quota_spin);
+
+	if (!x) {
+		gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags));
+		clear_bit(QDF_CHANGE, &qd->qd_flags);
+		qc->qc_flags = 0;
+		qc->qc_id = 0;
+		slot_put(qd);
+		qd_put(qd);
+	} else if (!test_and_set_bit(QDF_CHANGE, &qd->qd_flags)) {
+		qd_hold(qd);
+		slot_hold(qd);
+	}
+
+	mutex_unlock(&sdp->sd_quota_mutex);
+}
+
+/**
+ * gfs2_adjust_quota
+ *
+ * This function was mostly borrowed from gfs2_block_truncate_page which was
+ * in turn mostly borrowed from ext3
+ */
+static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+			     s64 change, struct gfs2_quota_data *qd)
+{
+	struct inode *inode = &ip->i_inode;
+	struct address_space *mapping = inode->i_mapping;
+	unsigned long index = loc >> PAGE_CACHE_SHIFT;
+	unsigned offset = loc & (PAGE_CACHE_SHIFT - 1);
+	unsigned blocksize, iblock, pos;
+	struct buffer_head *bh;
+	struct page *page;
+	void *kaddr;
+	__be64 *ptr;
+	s64 value;
+	int err = -EIO;
+
+	page = grab_cache_page(mapping, index);
+	if (!page)
+		return -ENOMEM;
+
+	blocksize = inode->i_sb->s_blocksize;
+	iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+
+	if (!page_has_buffers(page))
+		create_empty_buffers(page, blocksize, 0);
+
+	bh = page_buffers(page);
+	pos = blocksize;
+	while (offset >= pos) {
+		bh = bh->b_this_page;
+		iblock++;
+		pos += blocksize;
+	}
+
+	if (!buffer_mapped(bh)) {
+		gfs2_get_block(inode, iblock, bh, 1);
+		if (!buffer_mapped(bh))
+			goto unlock;
+	}
+
+	if (PageUptodate(page))
+		set_buffer_uptodate(bh);
+
+	if (!buffer_uptodate(bh)) {
+		ll_rw_block(READ_META, 1, &bh);
+		wait_on_buffer(bh);
+		if (!buffer_uptodate(bh))
+			goto unlock;
+	}
+
+	gfs2_trans_add_bh(ip->i_gl, bh, 0);
+
+	kaddr = kmap_atomic(page, KM_USER0);
+	ptr = kaddr + offset;
+	value = (s64)be64_to_cpu(*ptr) + change;
+	*ptr = cpu_to_be64(value);
+	flush_dcache_page(page);
+	kunmap_atomic(kaddr, KM_USER0);
+	err = 0;
+	qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC);
+	qd->qd_qb.qb_value = cpu_to_be64(value);
+unlock:
+	unlock_page(page);
+	page_cache_release(page);
+	return err;
+}
+
+static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
+{
+	struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd;
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+	unsigned int data_blocks, ind_blocks;
+	struct gfs2_holder *ghs, i_gh;
+	unsigned int qx, x;
+	struct gfs2_quota_data *qd;
+	loff_t offset;
+	unsigned int nalloc = 0;
+	struct gfs2_alloc *al = NULL;
+	int error;
+
+	gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota),
+			      &data_blocks, &ind_blocks);
+
+	ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_KERNEL);
+	if (!ghs)
+		return -ENOMEM;
+
+	sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL);
+	for (qx = 0; qx < num_qd; qx++) {
+		error = gfs2_glock_nq_init(qda[qx]->qd_gl,
+					   LM_ST_EXCLUSIVE,
+					   GL_NOCACHE, &ghs[qx]);
+		if (error)
+			goto out;
+	}
+
+	error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+	if (error)
+		goto out;
+
+	for (x = 0; x < num_qd; x++) {
+		int alloc_required;
+
+		offset = qd2offset(qda[x]);
+		error = gfs2_write_alloc_required(ip, offset,
+						  sizeof(struct gfs2_quota),
+						  &alloc_required);
+		if (error)
+			goto out_gunlock;
+		if (alloc_required)
+			nalloc++;
+	}
+
+	if (nalloc) {
+		al = gfs2_alloc_get(ip);
+
+		al->al_requested = nalloc * (data_blocks + ind_blocks);
+
+		error = gfs2_inplace_reserve(ip);
+		if (error)
+			goto out_alloc;
+
+		error = gfs2_trans_begin(sdp,
+					 al->al_rgd->rd_ri.ri_length +
+					 num_qd * data_blocks +
+					 nalloc * ind_blocks +
+					 RES_DINODE + num_qd +
+					 RES_STATFS, 0);
+		if (error)
+			goto out_ipres;
+	} else {
+		error = gfs2_trans_begin(sdp,
+					 num_qd * data_blocks +
+					 RES_DINODE + num_qd, 0);
+		if (error)
+			goto out_gunlock;
+	}
+
+	for (x = 0; x < num_qd; x++) {
+		qd = qda[x];
+		offset = qd2offset(qd);
+		error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync,
+					  (struct gfs2_quota_data *)
+					  qd->qd_gl->gl_lvb);
+		if (error)
+			goto out_end_trans;
+
+		do_qc(qd, -qd->qd_change_sync);
+	}
+
+	error = 0;
+
+out_end_trans:
+	gfs2_trans_end(sdp);
+out_ipres:
+	if (nalloc)
+		gfs2_inplace_release(ip);
+out_alloc:
+	if (nalloc)
+		gfs2_alloc_put(ip);
+out_gunlock:
+	gfs2_glock_dq_uninit(&i_gh);
+out:
+	while (qx--)
+		gfs2_glock_dq_uninit(&ghs[qx]);
+	kfree(ghs);
+	gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
+	return error;
+}
+
+static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
+		    struct gfs2_holder *q_gh)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+	struct gfs2_holder i_gh;
+	struct gfs2_quota q;
+	char buf[sizeof(struct gfs2_quota)];
+	struct file_ra_state ra_state;
+	int error;
+	struct gfs2_quota_lvb *qlvb;
+
+	file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping);
+restart:
+	error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh);
+	if (error)
+		return error;
+
+	qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
+
+	if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) {
+		loff_t pos;
+		gfs2_glock_dq_uninit(q_gh);
+		error = gfs2_glock_nq_init(qd->qd_gl,
+					  LM_ST_EXCLUSIVE, GL_NOCACHE,
+					  q_gh);
+		if (error)
+			return error;
+
+		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
+		if (error)
+			goto fail;
+
+		memset(buf, 0, sizeof(struct gfs2_quota));
+		pos = qd2offset(qd);
+		error = gfs2_internal_read(ip, &ra_state, buf,
+					   &pos, sizeof(struct gfs2_quota));
+		if (error < 0)
+			goto fail_gunlock;
+
+		gfs2_glock_dq_uninit(&i_gh);
+
+
+		gfs2_quota_in(&q, buf);
+		qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
+		qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC);
+		qlvb->__pad = 0;
+		qlvb->qb_limit = cpu_to_be64(q.qu_limit);
+		qlvb->qb_warn = cpu_to_be64(q.qu_warn);
+		qlvb->qb_value = cpu_to_be64(q.qu_value);
+		qd->qd_qb = *qlvb;
+
+		if (gfs2_glock_is_blocking(qd->qd_gl)) {
+			gfs2_glock_dq_uninit(q_gh);
+			force_refresh = 0;
+			goto restart;
+		}
+	}
+
+	return 0;
+
+fail_gunlock:
+	gfs2_glock_dq_uninit(&i_gh);
+fail:
+	gfs2_glock_dq_uninit(q_gh);
+	return error;
+}
+
+int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	unsigned int x;
+	int error = 0;
+
+	gfs2_quota_hold(ip, uid, gid);
+
+	if (capable(CAP_SYS_RESOURCE) ||
+	    sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
+		return 0;
+
+	sort(al->al_qd, al->al_qd_num, sizeof(struct gfs2_quota_data *),
+	     sort_qd, NULL);
+
+	for (x = 0; x < al->al_qd_num; x++) {
+		error = do_glock(al->al_qd[x], NO_FORCE, &al->al_qd_ghs[x]);
+		if (error)
+			break;
+	}
+
+	if (!error)
+		set_bit(GIF_QD_LOCKED, &ip->i_flags);
+	else {
+		while (x--)
+			gfs2_glock_dq_uninit(&al->al_qd_ghs[x]);
+		gfs2_quota_unhold(ip);
+	}
+
+	return error;
+}
+
+static int need_sync(struct gfs2_quota_data *qd)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+	struct gfs2_tune *gt = &sdp->sd_tune;
+	s64 value;
+	unsigned int num, den;
+	int do_sync = 1;
+
+	if (!qd->qd_qb.qb_limit)
+		return 0;
+
+	spin_lock(&sdp->sd_quota_spin);
+	value = qd->qd_change;
+	spin_unlock(&sdp->sd_quota_spin);
+
+	spin_lock(&gt->gt_spin);
+	num = gt->gt_quota_scale_num;
+	den = gt->gt_quota_scale_den;
+	spin_unlock(&gt->gt_spin);
+
+	if (value < 0)
+		do_sync = 0;
+	else if ((s64)be64_to_cpu(qd->qd_qb.qb_value) >=
+		 (s64)be64_to_cpu(qd->qd_qb.qb_limit))
+		do_sync = 0;
+	else {
+		value *= gfs2_jindex_size(sdp) * num;
+		do_div(value, den);
+		value += (s64)be64_to_cpu(qd->qd_qb.qb_value);
+		if (value < (s64)be64_to_cpu(qd->qd_qb.qb_limit))
+			do_sync = 0;
+	}
+
+	return do_sync;
+}
+
+void gfs2_quota_unlock(struct gfs2_inode *ip)
+{
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_quota_data *qda[4];
+	unsigned int count = 0;
+	unsigned int x;
+
+	if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags))
+		goto out;
+
+	for (x = 0; x < al->al_qd_num; x++) {
+		struct gfs2_quota_data *qd;
+		int sync;
+
+		qd = al->al_qd[x];
+		sync = need_sync(qd);
+
+		gfs2_glock_dq_uninit(&al->al_qd_ghs[x]);
+
+		if (sync && qd_trylock(qd))
+			qda[count++] = qd;
+	}
+
+	if (count) {
+		do_sync(count, qda);
+		for (x = 0; x < count; x++)
+			qd_unlock(qda[x]);
+	}
+
+out:
+	gfs2_quota_unhold(ip);
+}
+
+#define MAX_LINE 256
+
+static int print_message(struct gfs2_quota_data *qd, char *type)
+{
+	struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+	printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\r\n",
+	       sdp->sd_fsname, type,
+	       (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group",
+	       qd->qd_id);
+
+	return 0;
+}
+
+int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_quota_data *qd;
+	s64 value;
+	unsigned int x;
+	int error = 0;
+
+	if (!test_bit(GIF_QD_LOCKED, &ip->i_flags))
+		return 0;
+
+        if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
+                return 0;
+
+	for (x = 0; x < al->al_qd_num; x++) {
+		qd = al->al_qd[x];
+
+		if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
+		      (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))))
+			continue;
+
+		value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
+		spin_lock(&sdp->sd_quota_spin);
+		value += qd->qd_change;
+		spin_unlock(&sdp->sd_quota_spin);
+
+		if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
+			print_message(qd, "exceeded");
+			error = -EDQUOT;
+			break;
+		} else if (be64_to_cpu(qd->qd_qb.qb_warn) &&
+			   (s64)be64_to_cpu(qd->qd_qb.qb_warn) < value &&
+			   time_after_eq(jiffies, qd->qd_last_warn +
+					 gfs2_tune_get(sdp,
+						gt_quota_warn_period) * HZ)) {
+			error = print_message(qd, "warning");
+			qd->qd_last_warn = jiffies;
+		}
+	}
+
+	return error;
+}
+
+void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
+		       u32 uid, u32 gid)
+{
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_quota_data *qd;
+	unsigned int x;
+	unsigned int found = 0;
+
+	if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change))
+		return;
+	if (ip->i_di.di_flags & GFS2_DIF_SYSTEM)
+		return;
+
+	for (x = 0; x < al->al_qd_num; x++) {
+		qd = al->al_qd[x];
+
+		if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
+		    (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) {
+			do_qc(qd, change);
+			found++;
+		}
+	}
+}
+
+int gfs2_quota_sync(struct gfs2_sbd *sdp)
+{
+	struct gfs2_quota_data **qda;
+	unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync);
+	unsigned int num_qd;
+	unsigned int x;
+	int error = 0;
+
+	sdp->sd_quota_sync_gen++;
+
+	qda = kcalloc(max_qd, sizeof(struct gfs2_quota_data *), GFP_KERNEL);
+	if (!qda)
+		return -ENOMEM;
+
+	do {
+		num_qd = 0;
+
+		for (;;) {
+			error = qd_fish(sdp, qda + num_qd);
+			if (error || !qda[num_qd])
+				break;
+			if (++num_qd == max_qd)
+				break;
+		}
+
+		if (num_qd) {
+			if (!error)
+				error = do_sync(num_qd, qda);
+			if (!error)
+				for (x = 0; x < num_qd; x++)
+					qda[x]->qd_sync_gen =
+						sdp->sd_quota_sync_gen;
+
+			for (x = 0; x < num_qd; x++)
+				qd_unlock(qda[x]);
+		}
+	} while (!error && num_qd == max_qd);
+
+	kfree(qda);
+
+	return error;
+}
+
+int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
+{
+	struct gfs2_quota_data *qd;
+	struct gfs2_holder q_gh;
+	int error;
+
+	error = qd_get(sdp, user, id, CREATE, &qd);
+	if (error)
+		return error;
+
+	error = do_glock(qd, FORCE, &q_gh);
+	if (!error)
+		gfs2_glock_dq_uninit(&q_gh);
+
+	qd_put(qd);
+
+	return error;
+}
+
+int gfs2_quota_init(struct gfs2_sbd *sdp)
+{
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
+	unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift;
+	unsigned int x, slot = 0;
+	unsigned int found = 0;
+	u64 dblock;
+	u32 extlen = 0;
+	int error;
+
+	if (!ip->i_di.di_size || ip->i_di.di_size > (64 << 20) ||
+	    ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) {
+		gfs2_consist_inode(ip);
+		return -EIO;
+	}
+	sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block;
+	sdp->sd_quota_chunks = DIV_ROUND_UP(sdp->sd_quota_slots, 8 * PAGE_SIZE);
+
+	error = -ENOMEM;
+
+	sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks,
+				       sizeof(unsigned char *), GFP_KERNEL);
+	if (!sdp->sd_quota_bitmap)
+		return error;
+
+	for (x = 0; x < sdp->sd_quota_chunks; x++) {
+		sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL);
+		if (!sdp->sd_quota_bitmap[x])
+			goto fail;
+	}
+
+	for (x = 0; x < blocks; x++) {
+		struct buffer_head *bh;
+		unsigned int y;
+
+		if (!extlen) {
+			int new = 0;
+			error = gfs2_extent_map(&ip->i_inode, x, &new, &dblock, &extlen);
+			if (error)
+				goto fail;
+		}
+		error = -EIO;
+		bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
+		if (!bh)
+			goto fail;
+		if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) {
+			brelse(bh);
+			goto fail;
+		}
+
+		for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots;
+		     y++, slot++) {
+			struct gfs2_quota_change qc;
+			struct gfs2_quota_data *qd;
+
+			gfs2_quota_change_in(&qc, bh->b_data +
+					  sizeof(struct gfs2_meta_header) +
+					  y * sizeof(struct gfs2_quota_change));
+			if (!qc.qc_change)
+				continue;
+
+			error = qd_alloc(sdp, (qc.qc_flags & GFS2_QCF_USER),
+					 qc.qc_id, &qd);
+			if (error) {
+				brelse(bh);
+				goto fail;
+			}
+
+			set_bit(QDF_CHANGE, &qd->qd_flags);
+			qd->qd_change = qc.qc_change;
+			qd->qd_slot = slot;
+			qd->qd_slot_count = 1;
+			qd->qd_last_touched = jiffies;
+
+			spin_lock(&sdp->sd_quota_spin);
+			gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, slot, 1);
+			list_add(&qd->qd_list, &sdp->sd_quota_list);
+			atomic_inc(&sdp->sd_quota_count);
+			spin_unlock(&sdp->sd_quota_spin);
+
+			found++;
+		}
+
+		brelse(bh);
+		dblock++;
+		extlen--;
+	}
+
+	if (found)
+		fs_info(sdp, "found %u quota changes\n", found);
+
+	return 0;
+
+fail:
+	gfs2_quota_cleanup(sdp);
+	return error;
+}
+
+void gfs2_quota_scan(struct gfs2_sbd *sdp)
+{
+	struct gfs2_quota_data *qd, *safe;
+	LIST_HEAD(dead);
+
+	spin_lock(&sdp->sd_quota_spin);
+	list_for_each_entry_safe(qd, safe, &sdp->sd_quota_list, qd_list) {
+		if (!qd->qd_count &&
+		    time_after_eq(jiffies, qd->qd_last_touched +
+			        gfs2_tune_get(sdp, gt_quota_cache_secs) * HZ)) {
+			list_move(&qd->qd_list, &dead);
+			gfs2_assert_warn(sdp,
+					 atomic_read(&sdp->sd_quota_count) > 0);
+			atomic_dec(&sdp->sd_quota_count);
+		}
+	}
+	spin_unlock(&sdp->sd_quota_spin);
+
+	while (!list_empty(&dead)) {
+		qd = list_entry(dead.next, struct gfs2_quota_data, qd_list);
+		list_del(&qd->qd_list);
+
+		gfs2_assert_warn(sdp, !qd->qd_change);
+		gfs2_assert_warn(sdp, !qd->qd_slot_count);
+		gfs2_assert_warn(sdp, !qd->qd_bh_count);
+
+		gfs2_lvb_unhold(qd->qd_gl);
+		kfree(qd);
+	}
+}
+
+void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
+{
+	struct list_head *head = &sdp->sd_quota_list;
+	struct gfs2_quota_data *qd;
+	unsigned int x;
+
+	spin_lock(&sdp->sd_quota_spin);
+	while (!list_empty(head)) {
+		qd = list_entry(head->prev, struct gfs2_quota_data, qd_list);
+
+		if (qd->qd_count > 1 ||
+		    (qd->qd_count && !test_bit(QDF_CHANGE, &qd->qd_flags))) {
+			list_move(&qd->qd_list, head);
+			spin_unlock(&sdp->sd_quota_spin);
+			schedule();
+			spin_lock(&sdp->sd_quota_spin);
+			continue;
+		}
+
+		list_del(&qd->qd_list);
+		atomic_dec(&sdp->sd_quota_count);
+		spin_unlock(&sdp->sd_quota_spin);
+
+		if (!qd->qd_count) {
+			gfs2_assert_warn(sdp, !qd->qd_change);
+			gfs2_assert_warn(sdp, !qd->qd_slot_count);
+		} else
+			gfs2_assert_warn(sdp, qd->qd_slot_count == 1);
+		gfs2_assert_warn(sdp, !qd->qd_bh_count);
+
+		gfs2_lvb_unhold(qd->qd_gl);
+		kfree(qd);
+
+		spin_lock(&sdp->sd_quota_spin);
+	}
+	spin_unlock(&sdp->sd_quota_spin);
+
+	gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count));
+
+	if (sdp->sd_quota_bitmap) {
+		for (x = 0; x < sdp->sd_quota_chunks; x++)
+			kfree(sdp->sd_quota_bitmap[x]);
+		kfree(sdp->sd_quota_bitmap);
+	}
+}
+
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
new file mode 100644
index 0000000..a8be141
--- /dev/null
+++ b/fs/gfs2/quota.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __QUOTA_DOT_H__
+#define __QUOTA_DOT_H__
+
+struct gfs2_inode;
+struct gfs2_sbd;
+
+#define NO_QUOTA_CHANGE ((u32)-1)
+
+int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid);
+void gfs2_quota_unhold(struct gfs2_inode *ip);
+
+int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid);
+void gfs2_quota_unlock(struct gfs2_inode *ip);
+
+int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid);
+void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
+		       u32 uid, u32 gid);
+
+int gfs2_quota_sync(struct gfs2_sbd *sdp);
+int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id);
+
+int gfs2_quota_init(struct gfs2_sbd *sdp);
+void gfs2_quota_scan(struct gfs2_sbd *sdp);
+void gfs2_quota_cleanup(struct gfs2_sbd *sdp);
+
+#endif /* __QUOTA_DOT_H__ */
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
new file mode 100644
index 0000000..0a8a4b8
--- /dev/null
+++ b/fs/gfs2/recovery.c
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "glops.h"
+#include "lm.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "recovery.h"
+#include "super.h"
+#include "util.h"
+#include "dir.h"
+
+int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
+			   struct buffer_head **bh)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_glock *gl = ip->i_gl;
+	int new = 0;
+	u64 dblock;
+	u32 extlen;
+	int error;
+
+	error = gfs2_extent_map(&ip->i_inode, blk, &new, &dblock, &extlen);
+	if (error)
+		return error;
+	if (!dblock) {
+		gfs2_consist_inode(ip);
+		return -EIO;
+	}
+
+	*bh = gfs2_meta_ra(gl, dblock, extlen);
+
+	return error;
+}
+
+int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where)
+{
+	struct list_head *head = &sdp->sd_revoke_list;
+	struct gfs2_revoke_replay *rr;
+	int found = 0;
+
+	list_for_each_entry(rr, head, rr_list) {
+		if (rr->rr_blkno == blkno) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (found) {
+		rr->rr_where = where;
+		return 0;
+	}
+
+	rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_KERNEL);
+	if (!rr)
+		return -ENOMEM;
+
+	rr->rr_blkno = blkno;
+	rr->rr_where = where;
+	list_add(&rr->rr_list, head);
+
+	return 1;
+}
+
+int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where)
+{
+	struct gfs2_revoke_replay *rr;
+	int wrap, a, b, revoke;
+	int found = 0;
+
+	list_for_each_entry(rr, &sdp->sd_revoke_list, rr_list) {
+		if (rr->rr_blkno == blkno) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		return 0;
+
+	wrap = (rr->rr_where < sdp->sd_replay_tail);
+	a = (sdp->sd_replay_tail < where);
+	b = (where < rr->rr_where);
+	revoke = (wrap) ? (a || b) : (a && b);
+
+	return revoke;
+}
+
+void gfs2_revoke_clean(struct gfs2_sbd *sdp)
+{
+	struct list_head *head = &sdp->sd_revoke_list;
+	struct gfs2_revoke_replay *rr;
+
+	while (!list_empty(head)) {
+		rr = list_entry(head->next, struct gfs2_revoke_replay, rr_list);
+		list_del(&rr->rr_list);
+		kfree(rr);
+	}
+}
+
+/**
+ * get_log_header - read the log header for a given segment
+ * @jd: the journal
+ * @blk: the block to look at
+ * @lh: the log header to return
+ *
+ * Read the log header for a given segement in a given journal.  Do a few
+ * sanity checks on it.
+ *
+ * Returns: 0 on success,
+ *          1 if the header was invalid or incomplete,
+ *          errno on error
+ */
+
+static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
+			  struct gfs2_log_header *head)
+{
+	struct buffer_head *bh;
+	struct gfs2_log_header lh;
+	u32 hash;
+	int error;
+
+	error = gfs2_replay_read_block(jd, blk, &bh);
+	if (error)
+		return error;
+
+	memcpy(&lh, bh->b_data, sizeof(struct gfs2_log_header));
+	lh.lh_hash = 0;
+	hash = gfs2_disk_hash((char *)&lh, sizeof(struct gfs2_log_header));
+	gfs2_log_header_in(&lh, bh->b_data);
+
+	brelse(bh);
+
+	if (lh.lh_header.mh_magic != GFS2_MAGIC ||
+	    lh.lh_header.mh_type != GFS2_METATYPE_LH ||
+	    lh.lh_blkno != blk || lh.lh_hash != hash)
+		return 1;
+
+	*head = lh;
+
+	return 0;
+}
+
+/**
+ * find_good_lh - find a good log header
+ * @jd: the journal
+ * @blk: the segment to start searching from
+ * @lh: the log header to fill in
+ * @forward: if true search forward in the log, else search backward
+ *
+ * Call get_log_header() to get a log header for a segment, but if the
+ * segment is bad, either scan forward or backward until we find a good one.
+ *
+ * Returns: errno
+ */
+
+static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk,
+			struct gfs2_log_header *head)
+{
+	unsigned int orig_blk = *blk;
+	int error;
+
+	for (;;) {
+		error = get_log_header(jd, *blk, head);
+		if (error <= 0)
+			return error;
+
+		if (++*blk == jd->jd_blocks)
+			*blk = 0;
+
+		if (*blk == orig_blk) {
+			gfs2_consist_inode(GFS2_I(jd->jd_inode));
+			return -EIO;
+		}
+	}
+}
+
+/**
+ * jhead_scan - make sure we've found the head of the log
+ * @jd: the journal
+ * @head: this is filled in with the log descriptor of the head
+ *
+ * At this point, seg and lh should be either the head of the log or just
+ * before.  Scan forward until we find the head.
+ *
+ * Returns: errno
+ */
+
+static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
+{
+	unsigned int blk = head->lh_blkno;
+	struct gfs2_log_header lh;
+	int error;
+
+	for (;;) {
+		if (++blk == jd->jd_blocks)
+			blk = 0;
+
+		error = get_log_header(jd, blk, &lh);
+		if (error < 0)
+			return error;
+		if (error == 1)
+			continue;
+
+		if (lh.lh_sequence == head->lh_sequence) {
+			gfs2_consist_inode(GFS2_I(jd->jd_inode));
+			return -EIO;
+		}
+		if (lh.lh_sequence < head->lh_sequence)
+			break;
+
+		*head = lh;
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_find_jhead - find the head of a log
+ * @jd: the journal
+ * @head: the log descriptor for the head of the log is returned here
+ *
+ * Do a binary search of a journal and find the valid log entry with the
+ * highest sequence number.  (i.e. the log head)
+ *
+ * Returns: errno
+ */
+
+int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
+{
+	struct gfs2_log_header lh_1, lh_m;
+	u32 blk_1, blk_2, blk_m;
+	int error;
+
+	blk_1 = 0;
+	blk_2 = jd->jd_blocks - 1;
+
+	for (;;) {
+		blk_m = (blk_1 + blk_2) / 2;
+
+		error = find_good_lh(jd, &blk_1, &lh_1);
+		if (error)
+			return error;
+
+		error = find_good_lh(jd, &blk_m, &lh_m);
+		if (error)
+			return error;
+
+		if (blk_1 == blk_m || blk_m == blk_2)
+			break;
+
+		if (lh_1.lh_sequence <= lh_m.lh_sequence)
+			blk_1 = blk_m;
+		else
+			blk_2 = blk_m;
+	}
+
+	error = jhead_scan(jd, &lh_1);
+	if (error)
+		return error;
+
+	*head = lh_1;
+
+	return error;
+}
+
+/**
+ * foreach_descriptor - go through the active part of the log
+ * @jd: the journal
+ * @start: the first log header in the active region
+ * @end: the last log header (don't process the contents of this entry))
+ *
+ * Call a given function once for every log descriptor in the active
+ * portion of the log.
+ *
+ * Returns: errno
+ */
+
+static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start,
+			      unsigned int end, int pass)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+	struct buffer_head *bh;
+	struct gfs2_log_descriptor *ld;
+	int error = 0;
+	u32 length;
+	__be64 *ptr;
+	unsigned int offset = sizeof(struct gfs2_log_descriptor);
+	offset += sizeof(__be64) - 1;
+	offset &= ~(sizeof(__be64) - 1);
+
+	while (start != end) {
+		error = gfs2_replay_read_block(jd, start, &bh);
+		if (error)
+			return error;
+		if (gfs2_meta_check(sdp, bh)) {
+			brelse(bh);
+			return -EIO;
+		}
+		ld = (struct gfs2_log_descriptor *)bh->b_data;
+		length = be32_to_cpu(ld->ld_length);
+
+		if (be32_to_cpu(ld->ld_header.mh_type) == GFS2_METATYPE_LH) {
+			struct gfs2_log_header lh;
+			error = get_log_header(jd, start, &lh);
+			if (!error) {
+				gfs2_replay_incr_blk(sdp, &start);
+				brelse(bh);
+				continue;
+			}
+			if (error == 1) {
+				gfs2_consist_inode(GFS2_I(jd->jd_inode));
+				error = -EIO;
+			}
+			brelse(bh);
+			return error;
+		} else if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LD)) {
+			brelse(bh);
+			return -EIO;
+		}
+		ptr = (__be64 *)(bh->b_data + offset);
+		error = lops_scan_elements(jd, start, ld, ptr, pass);
+		if (error) {
+			brelse(bh);
+			return error;
+		}
+
+		while (length--)
+			gfs2_replay_incr_blk(sdp, &start);
+
+		brelse(bh);
+	}
+
+	return 0;
+}
+
+/**
+ * clean_journal - mark a dirty journal as being clean
+ * @sdp: the filesystem
+ * @jd: the journal
+ * @gl: the journal's glock
+ * @head: the head journal to start from
+ *
+ * Returns: errno
+ */
+
+static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+	unsigned int lblock;
+	struct gfs2_log_header *lh;
+	u32 hash;
+	struct buffer_head *bh;
+	int error;
+	struct buffer_head bh_map;
+
+	lblock = head->lh_blkno;
+	gfs2_replay_incr_blk(sdp, &lblock);
+	error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map, 1);
+	if (error)
+		return error;
+	if (!bh_map.b_blocknr) {
+		gfs2_consist_inode(ip);
+		return -EIO;
+	}
+
+	bh = sb_getblk(sdp->sd_vfs, bh_map.b_blocknr);
+	lock_buffer(bh);
+	memset(bh->b_data, 0, bh->b_size);
+	set_buffer_uptodate(bh);
+	clear_buffer_dirty(bh);
+	unlock_buffer(bh);
+
+	lh = (struct gfs2_log_header *)bh->b_data;
+	memset(lh, 0, sizeof(struct gfs2_log_header));
+	lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+	lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
+	lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
+	lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1);
+	lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT);
+	lh->lh_blkno = cpu_to_be32(lblock);
+	hash = gfs2_disk_hash((const char *)lh, sizeof(struct gfs2_log_header));
+	lh->lh_hash = cpu_to_be32(hash);
+
+	set_buffer_dirty(bh);
+	if (sync_dirty_buffer(bh))
+		gfs2_io_error_bh(sdp, bh);
+	brelse(bh);
+
+	return error;
+}
+
+/**
+ * gfs2_recover_journal - recovery a given journal
+ * @jd: the struct gfs2_jdesc describing the journal
+ *
+ * Acquire the journal's lock, check to see if the journal is clean, and
+ * do recovery if necessary.
+ *
+ * Returns: errno
+ */
+
+int gfs2_recover_journal(struct gfs2_jdesc *jd)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+	struct gfs2_log_header head;
+	struct gfs2_holder j_gh, ji_gh, t_gh;
+	unsigned long t;
+	int ro = 0;
+	unsigned int pass;
+	int error;
+
+	if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
+		fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n",
+			jd->jd_jid);
+
+		/* Aquire the journal lock so we can do recovery */
+
+		error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
+					  LM_ST_EXCLUSIVE,
+					  LM_FLAG_NOEXP | LM_FLAG_TRY | GL_NOCACHE,
+					  &j_gh);
+		switch (error) {
+		case 0:
+			break;
+
+		case GLR_TRYFAILED:
+			fs_info(sdp, "jid=%u: Busy\n", jd->jd_jid);
+			error = 0;
+
+		default:
+			goto fail;
+		};
+
+		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
+					   LM_FLAG_NOEXP, &ji_gh);
+		if (error)
+			goto fail_gunlock_j;
+	} else {
+		fs_info(sdp, "jid=%u, already locked for use\n", jd->jd_jid);
+	}
+
+	fs_info(sdp, "jid=%u: Looking at journal...\n", jd->jd_jid);
+
+	error = gfs2_jdesc_check(jd);
+	if (error)
+		goto fail_gunlock_ji;
+
+	error = gfs2_find_jhead(jd, &head);
+	if (error)
+		goto fail_gunlock_ji;
+
+	if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
+		fs_info(sdp, "jid=%u: Acquiring the transaction lock...\n",
+			jd->jd_jid);
+
+		t = jiffies;
+
+		/* Acquire a shared hold on the transaction lock */
+
+		error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
+					   LM_FLAG_NOEXP | LM_FLAG_PRIORITY |
+					   GL_NOCANCEL | GL_NOCACHE, &t_gh);
+		if (error)
+			goto fail_gunlock_ji;
+
+		if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) {
+			if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+				ro = 1;
+		} else {
+			if (sdp->sd_vfs->s_flags & MS_RDONLY)
+				ro = 1;
+		}
+
+		if (ro) {
+			fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n",
+				jd->jd_jid);
+			error = -EROFS;
+			goto fail_gunlock_tr;
+		}
+
+		fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid);
+
+		for (pass = 0; pass < 2; pass++) {
+			lops_before_scan(jd, &head, pass);
+			error = foreach_descriptor(jd, head.lh_tail,
+						   head.lh_blkno, pass);
+			lops_after_scan(jd, error, pass);
+			if (error)
+				goto fail_gunlock_tr;
+		}
+
+		error = clean_journal(jd, &head);
+		if (error)
+			goto fail_gunlock_tr;
+
+		gfs2_glock_dq_uninit(&t_gh);
+		t = DIV_ROUND_UP(jiffies - t, HZ);
+		fs_info(sdp, "jid=%u: Journal replayed in %lus\n",
+			jd->jd_jid, t);
+	}
+
+	if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
+		gfs2_glock_dq_uninit(&ji_gh);
+
+	gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS);
+
+	if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
+		gfs2_glock_dq_uninit(&j_gh);
+
+	fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
+	return 0;
+
+fail_gunlock_tr:
+	gfs2_glock_dq_uninit(&t_gh);
+fail_gunlock_ji:
+	if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
+		gfs2_glock_dq_uninit(&ji_gh);
+fail_gunlock_j:
+		gfs2_glock_dq_uninit(&j_gh);
+	}
+
+	fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
+
+fail:
+	gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
+	return error;
+}
+
+/**
+ * gfs2_check_journals - Recover any dirty journals
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_check_journals(struct gfs2_sbd *sdp)
+{
+	struct gfs2_jdesc *jd;
+
+	for (;;) {
+		jd = gfs2_jdesc_find_dirty(sdp);
+		if (!jd)
+			break;
+
+		if (jd != sdp->sd_jdesc)
+			gfs2_recover_journal(jd);
+	}
+}
+
diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h
new file mode 100644
index 0000000..961feed
--- /dev/null
+++ b/fs/gfs2/recovery.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __RECOVERY_DOT_H__
+#define __RECOVERY_DOT_H__
+
+#include "incore.h"
+
+static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk)
+{
+	if (++*blk == sdp->sd_jdesc->jd_blocks)
+	        *blk = 0;
+}
+
+int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
+			   struct buffer_head **bh);
+
+int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where);
+int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where);
+void gfs2_revoke_clean(struct gfs2_sbd *sdp);
+
+int gfs2_find_jhead(struct gfs2_jdesc *jd,
+		    struct gfs2_log_header *head);
+int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
+void gfs2_check_journals(struct gfs2_sbd *sdp);
+
+#endif /* __RECOVERY_DOT_H__ */
+
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
new file mode 100644
index 0000000..b261385
--- /dev/null
+++ b/fs/gfs2/rgrp.c
@@ -0,0 +1,1513 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "glops.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "super.h"
+#include "trans.h"
+#include "ops_file.h"
+#include "util.h"
+
+#define BFITNOENT ((u32)~0)
+
+/*
+ * These routines are used by the resource group routines (rgrp.c)
+ * to keep track of block allocation.  Each block is represented by two
+ * bits.  So, each byte represents GFS2_NBBY (i.e. 4) blocks.
+ *
+ * 0 = Free
+ * 1 = Used (not metadata)
+ * 2 = Unlinked (still in use) inode
+ * 3 = Used (metadata)
+ */
+
+static const char valid_change[16] = {
+	        /* current */
+	/* n */ 0, 1, 1, 1,
+	/* e */ 1, 0, 0, 0,
+	/* w */ 0, 0, 0, 1,
+	        1, 0, 0, 0
+};
+
+/**
+ * gfs2_setbit - Set a bit in the bitmaps
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @block: the block to set
+ * @new_state: the new state of the block
+ *
+ */
+
+static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+			unsigned int buflen, u32 block,
+			unsigned char new_state)
+{
+	unsigned char *byte, *end, cur_state;
+	unsigned int bit;
+
+	byte = buffer + (block / GFS2_NBBY);
+	bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
+	end = buffer + buflen;
+
+	gfs2_assert(rgd->rd_sbd, byte < end);
+
+	cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+
+	if (valid_change[new_state * 4 + cur_state]) {
+		*byte ^= cur_state << bit;
+		*byte |= new_state << bit;
+	} else
+		gfs2_consist_rgrpd(rgd);
+}
+
+/**
+ * gfs2_testbit - test a bit in the bitmaps
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @block: the block to read
+ *
+ */
+
+static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+				  unsigned int buflen, u32 block)
+{
+	unsigned char *byte, *end, cur_state;
+	unsigned int bit;
+
+	byte = buffer + (block / GFS2_NBBY);
+	bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
+	end = buffer + buflen;
+
+	gfs2_assert(rgd->rd_sbd, byte < end);
+
+	cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+
+	return cur_state;
+}
+
+/**
+ * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing
+ *       a block in a given allocation state.
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @goal: start search at this block's bit-pair (within @buffer)
+ * @old_state: GFS2_BLKST_XXX the state of the block we're looking for;
+ *       bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0)
+ *
+ * Scope of @goal and returned block number is only within this bitmap buffer,
+ * not entire rgrp or filesystem.  @buffer will be offset from the actual
+ * beginning of a bitmap block buffer, skipping any header structures.
+ *
+ * Return: the block number (bitmap buffer scope) that was found
+ */
+
+static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+			    unsigned int buflen, u32 goal,
+			    unsigned char old_state)
+{
+	unsigned char *byte, *end, alloc;
+	u32 blk = goal;
+	unsigned int bit;
+
+	byte = buffer + (goal / GFS2_NBBY);
+	bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
+	end = buffer + buflen;
+	alloc = (old_state & 1) ? 0 : 0x55;
+
+	while (byte < end) {
+		if ((*byte & 0x55) == alloc) {
+			blk += (8 - bit) >> 1;
+
+			bit = 0;
+			byte++;
+
+			continue;
+		}
+
+		if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
+			return blk;
+
+		bit += GFS2_BIT_SIZE;
+		if (bit >= 8) {
+			bit = 0;
+			byte++;
+		}
+
+		blk++;
+	}
+
+	return BFITNOENT;
+}
+
+/**
+ * gfs2_bitcount - count the number of bits in a certain state
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @state: the state of the block we're looking for
+ *
+ * Returns: The number of bits
+ */
+
+static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+			      unsigned int buflen, unsigned char state)
+{
+	unsigned char *byte = buffer;
+	unsigned char *end = buffer + buflen;
+	unsigned char state1 = state << 2;
+	unsigned char state2 = state << 4;
+	unsigned char state3 = state << 6;
+	u32 count = 0;
+
+	for (; byte < end; byte++) {
+		if (((*byte) & 0x03) == state)
+			count++;
+		if (((*byte) & 0x0C) == state1)
+			count++;
+		if (((*byte) & 0x30) == state2)
+			count++;
+		if (((*byte) & 0xC0) == state3)
+			count++;
+	}
+
+	return count;
+}
+
+/**
+ * gfs2_rgrp_verify - Verify that a resource group is consistent
+ * @sdp: the filesystem
+ * @rgd: the rgrp
+ *
+ */
+
+void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	struct gfs2_bitmap *bi = NULL;
+	u32 length = rgd->rd_ri.ri_length;
+	u32 count[4], tmp;
+	int buf, x;
+
+	memset(count, 0, 4 * sizeof(u32));
+
+	/* Count # blocks in each of 4 possible allocation states */
+	for (buf = 0; buf < length; buf++) {
+		bi = rgd->rd_bits + buf;
+		for (x = 0; x < 4; x++)
+			count[x] += gfs2_bitcount(rgd,
+						  bi->bi_bh->b_data +
+						  bi->bi_offset,
+						  bi->bi_len, x);
+	}
+
+	if (count[0] != rgd->rd_rg.rg_free) {
+		if (gfs2_consist_rgrpd(rgd))
+			fs_err(sdp, "free data mismatch:  %u != %u\n",
+			       count[0], rgd->rd_rg.rg_free);
+		return;
+	}
+
+	tmp = rgd->rd_ri.ri_data -
+		rgd->rd_rg.rg_free -
+		rgd->rd_rg.rg_dinodes;
+	if (count[1] + count[2] != tmp) {
+		if (gfs2_consist_rgrpd(rgd))
+			fs_err(sdp, "used data mismatch:  %u != %u\n",
+			       count[1], tmp);
+		return;
+	}
+
+	if (count[3] != rgd->rd_rg.rg_dinodes) {
+		if (gfs2_consist_rgrpd(rgd))
+			fs_err(sdp, "used metadata mismatch:  %u != %u\n",
+			       count[3], rgd->rd_rg.rg_dinodes);
+		return;
+	}
+
+	if (count[2] > count[3]) {
+		if (gfs2_consist_rgrpd(rgd))
+			fs_err(sdp, "unlinked inodes > inodes:  %u\n",
+			       count[2]);
+		return;
+	}
+
+}
+
+static inline int rgrp_contains_block(struct gfs2_rindex *ri, u64 block)
+{
+	u64 first = ri->ri_data0;
+	u64 last = first + ri->ri_data;
+	return first <= block && block < last;
+}
+
+/**
+ * gfs2_blk2rgrpd - Find resource group for a given data/meta block number
+ * @sdp: The GFS2 superblock
+ * @n: The data block number
+ *
+ * Returns: The resource group, or NULL if not found
+ */
+
+struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
+{
+	struct gfs2_rgrpd *rgd;
+
+	spin_lock(&sdp->sd_rindex_spin);
+
+	list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) {
+		if (rgrp_contains_block(&rgd->rd_ri, blk)) {
+			list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
+			spin_unlock(&sdp->sd_rindex_spin);
+			return rgd;
+		}
+	}
+
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	return NULL;
+}
+
+/**
+ * gfs2_rgrpd_get_first - get the first Resource Group in the filesystem
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: The first rgrp in the filesystem
+ */
+
+struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp)
+{
+	gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list));
+	return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list);
+}
+
+/**
+ * gfs2_rgrpd_get_next - get the next RG
+ * @rgd: A RG
+ *
+ * Returns: The next rgrp
+ */
+
+struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd)
+{
+	if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list)
+		return NULL;
+	return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list);
+}
+
+static void clear_rgrpdi(struct gfs2_sbd *sdp)
+{
+	struct list_head *head;
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_glock *gl;
+
+	spin_lock(&sdp->sd_rindex_spin);
+	sdp->sd_rindex_forward = NULL;
+	head = &sdp->sd_rindex_recent_list;
+	while (!list_empty(head)) {
+		rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);
+		list_del(&rgd->rd_recent);
+	}
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	head = &sdp->sd_rindex_list;
+	while (!list_empty(head)) {
+		rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list);
+		gl = rgd->rd_gl;
+
+		list_del(&rgd->rd_list);
+		list_del(&rgd->rd_list_mru);
+
+		if (gl) {
+			gl->gl_object = NULL;
+			gfs2_glock_put(gl);
+		}
+
+		kfree(rgd->rd_bits);
+		kfree(rgd);
+	}
+}
+
+void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
+{
+	mutex_lock(&sdp->sd_rindex_mutex);
+	clear_rgrpdi(sdp);
+	mutex_unlock(&sdp->sd_rindex_mutex);
+}
+
+/**
+ * gfs2_compute_bitstructs - Compute the bitmap sizes
+ * @rgd: The resource group descriptor
+ *
+ * Calculates bitmap descriptors, one for each block that contains bitmap data
+ *
+ * Returns: errno
+ */
+
+static int compute_bitstructs(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	struct gfs2_bitmap *bi;
+	u32 length = rgd->rd_ri.ri_length; /* # blocks in hdr & bitmap */
+	u32 bytes_left, bytes;
+	int x;
+
+	if (!length)
+		return -EINVAL;
+
+	rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_NOFS);
+	if (!rgd->rd_bits)
+		return -ENOMEM;
+
+	bytes_left = rgd->rd_ri.ri_bitbytes;
+
+	for (x = 0; x < length; x++) {
+		bi = rgd->rd_bits + x;
+
+		/* small rgrp; bitmap stored completely in header block */
+		if (length == 1) {
+			bytes = bytes_left;
+			bi->bi_offset = sizeof(struct gfs2_rgrp);
+			bi->bi_start = 0;
+			bi->bi_len = bytes;
+		/* header block */
+		} else if (x == 0) {
+			bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp);
+			bi->bi_offset = sizeof(struct gfs2_rgrp);
+			bi->bi_start = 0;
+			bi->bi_len = bytes;
+		/* last block */
+		} else if (x + 1 == length) {
+			bytes = bytes_left;
+			bi->bi_offset = sizeof(struct gfs2_meta_header);
+			bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left;
+			bi->bi_len = bytes;
+		/* other blocks */
+		} else {
+			bytes = sdp->sd_sb.sb_bsize -
+				sizeof(struct gfs2_meta_header);
+			bi->bi_offset = sizeof(struct gfs2_meta_header);
+			bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left;
+			bi->bi_len = bytes;
+		}
+
+		bytes_left -= bytes;
+	}
+
+	if (bytes_left) {
+		gfs2_consist_rgrpd(rgd);
+		return -EIO;
+	}
+	bi = rgd->rd_bits + (length - 1);
+	if ((bi->bi_start + bi->bi_len) * GFS2_NBBY != rgd->rd_ri.ri_data) {
+		if (gfs2_consist_rgrpd(rgd)) {
+			gfs2_rindex_print(&rgd->rd_ri);
+			fs_err(sdp, "start=%u len=%u offset=%u\n",
+			       bi->bi_start, bi->bi_len, bi->bi_offset);
+		}
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_ri_update - Pull in a new resource index from the disk
+ * @gl: The glock covering the rindex inode
+ *
+ * Returns: 0 on successful update, error code otherwise
+ */
+
+static int gfs2_ri_update(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct inode *inode = &ip->i_inode;
+	struct gfs2_rgrpd *rgd;
+	char buf[sizeof(struct gfs2_rindex)];
+	struct file_ra_state ra_state;
+	u64 junk = ip->i_di.di_size;
+	int error;
+
+	if (do_div(junk, sizeof(struct gfs2_rindex))) {
+		gfs2_consist_inode(ip);
+		return -EIO;
+	}
+
+	clear_rgrpdi(sdp);
+
+	file_ra_state_init(&ra_state, inode->i_mapping);
+	for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) {
+		loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
+		error = gfs2_internal_read(ip, &ra_state, buf, &pos,
+					    sizeof(struct gfs2_rindex));
+		if (!error)
+			break;
+		if (error != sizeof(struct gfs2_rindex)) {
+			if (error > 0)
+				error = -EIO;
+			goto fail;
+		}
+
+		rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_NOFS);
+		error = -ENOMEM;
+		if (!rgd)
+			goto fail;
+
+		mutex_init(&rgd->rd_mutex);
+		lops_init_le(&rgd->rd_le, &gfs2_rg_lops);
+		rgd->rd_sbd = sdp;
+
+		list_add_tail(&rgd->rd_list, &sdp->sd_rindex_list);
+		list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
+
+		gfs2_rindex_in(&rgd->rd_ri, buf);
+		error = compute_bitstructs(rgd);
+		if (error)
+			goto fail;
+
+		error = gfs2_glock_get(sdp, rgd->rd_ri.ri_addr,
+				       &gfs2_rgrp_glops, CREATE, &rgd->rd_gl);
+		if (error)
+			goto fail;
+
+		rgd->rd_gl->gl_object = rgd;
+		rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1;
+	}
+
+	sdp->sd_rindex_vn = ip->i_gl->gl_vn;
+	return 0;
+
+fail:
+	clear_rgrpdi(sdp);
+	return error;
+}
+
+/**
+ * gfs2_rindex_hold - Grab a lock on the rindex
+ * @sdp: The GFS2 superblock
+ * @ri_gh: the glock holder
+ *
+ * We grab a lock on the rindex inode to make sure that it doesn't
+ * change whilst we are performing an operation. We keep this lock
+ * for quite long periods of time compared to other locks. This
+ * doesn't matter, since it is shared and it is very, very rarely
+ * accessed in the exclusive mode (i.e. only when expanding the filesystem).
+ *
+ * This makes sure that we're using the latest copy of the resource index
+ * special file, which might have been updated if someone expanded the
+ * filesystem (via gfs2_grow utility), which adds new resource groups.
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh)
+{
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
+	struct gfs2_glock *gl = ip->i_gl;
+	int error;
+
+	error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);
+	if (error)
+		return error;
+
+	/* Read new copy from disk if we don't have the latest */
+	if (sdp->sd_rindex_vn != gl->gl_vn) {
+		mutex_lock(&sdp->sd_rindex_mutex);
+		if (sdp->sd_rindex_vn != gl->gl_vn) {
+			error = gfs2_ri_update(ip);
+			if (error)
+				gfs2_glock_dq_uninit(ri_gh);
+		}
+		mutex_unlock(&sdp->sd_rindex_mutex);
+	}
+
+	return error;
+}
+
+/**
+ * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps
+ * @rgd: the struct gfs2_rgrpd describing the RG to read in
+ *
+ * Read in all of a Resource Group's header and bitmap blocks.
+ * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps.
+ *
+ * Returns: errno
+ */
+
+int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	struct gfs2_glock *gl = rgd->rd_gl;
+	unsigned int length = rgd->rd_ri.ri_length;
+	struct gfs2_bitmap *bi;
+	unsigned int x, y;
+	int error;
+
+	mutex_lock(&rgd->rd_mutex);
+
+	spin_lock(&sdp->sd_rindex_spin);
+	if (rgd->rd_bh_count) {
+		rgd->rd_bh_count++;
+		spin_unlock(&sdp->sd_rindex_spin);
+		mutex_unlock(&rgd->rd_mutex);
+		return 0;
+	}
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	for (x = 0; x < length; x++) {
+		bi = rgd->rd_bits + x;
+		error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, 0, &bi->bi_bh);
+		if (error)
+			goto fail;
+	}
+
+	for (y = length; y--;) {
+		bi = rgd->rd_bits + y;
+		error = gfs2_meta_wait(sdp, bi->bi_bh);
+		if (error)
+			goto fail;
+		if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB :
+					      GFS2_METATYPE_RG)) {
+			error = -EIO;
+			goto fail;
+		}
+	}
+
+	if (rgd->rd_rg_vn != gl->gl_vn) {
+		gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data);
+		rgd->rd_rg_vn = gl->gl_vn;
+	}
+
+	spin_lock(&sdp->sd_rindex_spin);
+	rgd->rd_free_clone = rgd->rd_rg.rg_free;
+	rgd->rd_bh_count++;
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	mutex_unlock(&rgd->rd_mutex);
+
+	return 0;
+
+fail:
+	while (x--) {
+		bi = rgd->rd_bits + x;
+		brelse(bi->bi_bh);
+		bi->bi_bh = NULL;
+		gfs2_assert_warn(sdp, !bi->bi_clone);
+	}
+	mutex_unlock(&rgd->rd_mutex);
+
+	return error;
+}
+
+void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+
+	spin_lock(&sdp->sd_rindex_spin);
+	gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
+	rgd->rd_bh_count++;
+	spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get()
+ * @rgd: the struct gfs2_rgrpd describing the RG to read in
+ *
+ */
+
+void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	int x, length = rgd->rd_ri.ri_length;
+
+	spin_lock(&sdp->sd_rindex_spin);
+	gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
+	if (--rgd->rd_bh_count) {
+		spin_unlock(&sdp->sd_rindex_spin);
+		return;
+	}
+
+	for (x = 0; x < length; x++) {
+		struct gfs2_bitmap *bi = rgd->rd_bits + x;
+		kfree(bi->bi_clone);
+		bi->bi_clone = NULL;
+		brelse(bi->bi_bh);
+		bi->bi_bh = NULL;
+	}
+
+	spin_unlock(&sdp->sd_rindex_spin);
+}
+
+void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	unsigned int length = rgd->rd_ri.ri_length;
+	unsigned int x;
+
+	for (x = 0; x < length; x++) {
+		struct gfs2_bitmap *bi = rgd->rd_bits + x;
+		if (!bi->bi_clone)
+			continue;
+		memcpy(bi->bi_clone + bi->bi_offset,
+		       bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
+	}
+
+	spin_lock(&sdp->sd_rindex_spin);
+	rgd->rd_free_clone = rgd->rd_rg.rg_free;
+	spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode
+ * @ip: the incore GFS2 inode structure
+ *
+ * Returns: the struct gfs2_alloc
+ */
+
+struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
+{
+	struct gfs2_alloc *al = &ip->i_alloc;
+
+	/* FIXME: Should assert that the correct locks are held here... */
+	memset(al, 0, sizeof(*al));
+	return al;
+}
+
+/**
+ * try_rgrp_fit - See if a given reservation will fit in a given RG
+ * @rgd: the RG data
+ * @al: the struct gfs2_alloc structure describing the reservation
+ *
+ * If there's room for the requested blocks to be allocated from the RG:
+ *   Sets the $al_reserved_data field in @al.
+ *   Sets the $al_reserved_meta field in @al.
+ *   Sets the $al_rgd field in @al.
+ *
+ * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
+ */
+
+static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	int ret = 0;
+
+	spin_lock(&sdp->sd_rindex_spin);
+	if (rgd->rd_free_clone >= al->al_requested) {
+		al->al_rgd = rgd;
+		ret = 1;
+	}
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	return ret;
+}
+
+/**
+ * recent_rgrp_first - get first RG from "recent" list
+ * @sdp: The GFS2 superblock
+ * @rglast: address of the rgrp used last
+ *
+ * Returns: The first rgrp in the recent list
+ */
+
+static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp,
+					    u64 rglast)
+{
+	struct gfs2_rgrpd *rgd = NULL;
+
+	spin_lock(&sdp->sd_rindex_spin);
+
+	if (list_empty(&sdp->sd_rindex_recent_list))
+		goto out;
+
+	if (!rglast)
+		goto first;
+
+	list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
+		if (rgd->rd_ri.ri_addr == rglast)
+			goto out;
+	}
+
+first:
+	rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd,
+			 rd_recent);
+out:
+	spin_unlock(&sdp->sd_rindex_spin);
+	return rgd;
+}
+
+/**
+ * recent_rgrp_next - get next RG from "recent" list
+ * @cur_rgd: current rgrp
+ * @remove:
+ *
+ * Returns: The next rgrp in the recent list
+ */
+
+static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd,
+					   int remove)
+{
+	struct gfs2_sbd *sdp = cur_rgd->rd_sbd;
+	struct list_head *head;
+	struct gfs2_rgrpd *rgd;
+
+	spin_lock(&sdp->sd_rindex_spin);
+
+	head = &sdp->sd_rindex_recent_list;
+
+	list_for_each_entry(rgd, head, rd_recent) {
+		if (rgd == cur_rgd) {
+			if (cur_rgd->rd_recent.next != head)
+				rgd = list_entry(cur_rgd->rd_recent.next,
+						 struct gfs2_rgrpd, rd_recent);
+			else
+				rgd = NULL;
+
+			if (remove)
+				list_del(&cur_rgd->rd_recent);
+
+			goto out;
+		}
+	}
+
+	rgd = NULL;
+	if (!list_empty(head))
+		rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);
+
+out:
+	spin_unlock(&sdp->sd_rindex_spin);
+	return rgd;
+}
+
+/**
+ * recent_rgrp_add - add an RG to tail of "recent" list
+ * @new_rgd: The rgrp to add
+ *
+ */
+
+static void recent_rgrp_add(struct gfs2_rgrpd *new_rgd)
+{
+	struct gfs2_sbd *sdp = new_rgd->rd_sbd;
+	struct gfs2_rgrpd *rgd;
+	unsigned int count = 0;
+	unsigned int max = sdp->sd_rgrps / gfs2_jindex_size(sdp);
+
+	spin_lock(&sdp->sd_rindex_spin);
+
+	list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
+		if (rgd == new_rgd)
+			goto out;
+
+		if (++count >= max)
+			goto out;
+	}
+	list_add_tail(&new_rgd->rd_recent, &sdp->sd_rindex_recent_list);
+
+out:
+	spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * forward_rgrp_get - get an rgrp to try next from full list
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: The rgrp to try next
+ */
+
+static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp)
+{
+	struct gfs2_rgrpd *rgd;
+	unsigned int journals = gfs2_jindex_size(sdp);
+	unsigned int rg = 0, x;
+
+	spin_lock(&sdp->sd_rindex_spin);
+
+	rgd = sdp->sd_rindex_forward;
+	if (!rgd) {
+		if (sdp->sd_rgrps >= journals)
+			rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals;
+
+		for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg;
+		     x++, rgd = gfs2_rgrpd_get_next(rgd))
+			/* Do Nothing */;
+
+		sdp->sd_rindex_forward = rgd;
+	}
+
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	return rgd;
+}
+
+/**
+ * forward_rgrp_set - set the forward rgrp pointer
+ * @sdp: the filesystem
+ * @rgd: The new forward rgrp
+ *
+ */
+
+static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd)
+{
+	spin_lock(&sdp->sd_rindex_spin);
+	sdp->sd_rindex_forward = rgd;
+	spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * get_local_rgrp - Choose and lock a rgrp for allocation
+ * @ip: the inode to reserve space for
+ * @rgp: the chosen and locked rgrp
+ *
+ * Try to acquire rgrp in way which avoids contending with others.
+ *
+ * Returns: errno
+ */
+
+static int get_local_rgrp(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_rgrpd *rgd, *begin = NULL;
+	struct gfs2_alloc *al = &ip->i_alloc;
+	int flags = LM_FLAG_TRY;
+	int skipped = 0;
+	int loops = 0;
+	int error;
+
+	/* Try recently successful rgrps */
+
+	rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
+
+	while (rgd) {
+		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
+					   LM_FLAG_TRY, &al->al_rgd_gh);
+		switch (error) {
+		case 0:
+			if (try_rgrp_fit(rgd, al))
+				goto out;
+			gfs2_glock_dq_uninit(&al->al_rgd_gh);
+			rgd = recent_rgrp_next(rgd, 1);
+			break;
+
+		case GLR_TRYFAILED:
+			rgd = recent_rgrp_next(rgd, 0);
+			break;
+
+		default:
+			return error;
+		}
+	}
+
+	/* Go through full list of rgrps */
+
+	begin = rgd = forward_rgrp_get(sdp);
+
+	for (;;) {
+		error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
+					  &al->al_rgd_gh);
+		switch (error) {
+		case 0:
+			if (try_rgrp_fit(rgd, al))
+				goto out;
+			gfs2_glock_dq_uninit(&al->al_rgd_gh);
+			break;
+
+		case GLR_TRYFAILED:
+			skipped++;
+			break;
+
+		default:
+			return error;
+		}
+
+		rgd = gfs2_rgrpd_get_next(rgd);
+		if (!rgd)
+			rgd = gfs2_rgrpd_get_first(sdp);
+
+		if (rgd == begin) {
+			if (++loops >= 2 || !skipped)
+				return -ENOSPC;
+			flags = 0;
+		}
+	}
+
+out:
+	ip->i_last_rg_alloc = rgd->rd_ri.ri_addr;
+
+	if (begin) {
+		recent_rgrp_add(rgd);
+		rgd = gfs2_rgrpd_get_next(rgd);
+		if (!rgd)
+			rgd = gfs2_rgrpd_get_first(sdp);
+		forward_rgrp_set(sdp, rgd);
+	}
+
+	return 0;
+}
+
+/**
+ * gfs2_inplace_reserve_i - Reserve space in the filesystem
+ * @ip: the inode to reserve space for
+ *
+ * Returns: errno
+ */
+
+int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	int error;
+
+	if (gfs2_assert_warn(sdp, al->al_requested))
+		return -EINVAL;
+
+	error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
+	if (error)
+		return error;
+
+	error = get_local_rgrp(ip);
+	if (error) {
+		gfs2_glock_dq_uninit(&al->al_ri_gh);
+		return error;
+	}
+
+	al->al_file = file;
+	al->al_line = line;
+
+	return 0;
+}
+
+/**
+ * gfs2_inplace_release - release an inplace reservation
+ * @ip: the inode the reservation was taken out on
+ *
+ * Release a reservation made by gfs2_inplace_reserve().
+ */
+
+void gfs2_inplace_release(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+
+	if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
+		fs_warn(sdp, "al_alloced = %u, al_requested = %u "
+			     "al_file = %s, al_line = %u\n",
+		             al->al_alloced, al->al_requested, al->al_file,
+			     al->al_line);
+
+	al->al_rgd = NULL;
+	gfs2_glock_dq_uninit(&al->al_rgd_gh);
+	gfs2_glock_dq_uninit(&al->al_ri_gh);
+}
+
+/**
+ * gfs2_get_block_type - Check a block in a RG is of given type
+ * @rgd: the resource group holding the block
+ * @block: the block number
+ *
+ * Returns: The block type (GFS2_BLKST_*)
+ */
+
+unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
+{
+	struct gfs2_bitmap *bi = NULL;
+	u32 length, rgrp_block, buf_block;
+	unsigned int buf;
+	unsigned char type;
+
+	length = rgd->rd_ri.ri_length;
+	rgrp_block = block - rgd->rd_ri.ri_data0;
+
+	for (buf = 0; buf < length; buf++) {
+		bi = rgd->rd_bits + buf;
+		if (rgrp_block < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
+			break;
+	}
+
+	gfs2_assert(rgd->rd_sbd, buf < length);
+	buf_block = rgrp_block - bi->bi_start * GFS2_NBBY;
+
+	type = gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+			   bi->bi_len, buf_block);
+
+	return type;
+}
+
+/**
+ * rgblk_search - find a block in @old_state, change allocation
+ *           state to @new_state
+ * @rgd: the resource group descriptor
+ * @goal: the goal block within the RG (start here to search for avail block)
+ * @old_state: GFS2_BLKST_XXX the before-allocation state to find
+ * @new_state: GFS2_BLKST_XXX the after-allocation block state
+ *
+ * Walk rgrp's bitmap to find bits that represent a block in @old_state.
+ * Add the found bitmap buffer to the transaction.
+ * Set the found bits to @new_state to change block's allocation state.
+ *
+ * This function never fails, because we wouldn't call it unless we
+ * know (from reservation results, etc.) that a block is available.
+ *
+ * Scope of @goal and returned block is just within rgrp, not the whole
+ * filesystem.
+ *
+ * Returns:  the block number allocated
+ */
+
+static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
+			     unsigned char old_state, unsigned char new_state)
+{
+	struct gfs2_bitmap *bi = NULL;
+	u32 length = rgd->rd_ri.ri_length;
+	u32 blk = 0;
+	unsigned int buf, x;
+
+	/* Find bitmap block that contains bits for goal block */
+	for (buf = 0; buf < length; buf++) {
+		bi = rgd->rd_bits + buf;
+		if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
+			break;
+	}
+
+	gfs2_assert(rgd->rd_sbd, buf < length);
+
+	/* Convert scope of "goal" from rgrp-wide to within found bit block */
+	goal -= bi->bi_start * GFS2_NBBY;
+
+	/* Search (up to entire) bitmap in this rgrp for allocatable block.
+	   "x <= length", instead of "x < length", because we typically start
+	   the search in the middle of a bit block, but if we can't find an
+	   allocatable block anywhere else, we want to be able wrap around and
+	   search in the first part of our first-searched bit block.  */
+	for (x = 0; x <= length; x++) {
+		if (bi->bi_clone)
+			blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
+					  bi->bi_len, goal, old_state);
+		else
+			blk = gfs2_bitfit(rgd,
+					  bi->bi_bh->b_data + bi->bi_offset,
+					  bi->bi_len, goal, old_state);
+		if (blk != BFITNOENT)
+			break;
+
+		/* Try next bitmap block (wrap back to rgrp header if at end) */
+		buf = (buf + 1) % length;
+		bi = rgd->rd_bits + buf;
+		goal = 0;
+	}
+
+	if (gfs2_assert_withdraw(rgd->rd_sbd, x <= length))
+		blk = 0;
+
+	gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
+	gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+		    bi->bi_len, blk, new_state);
+	if (bi->bi_clone)
+		gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset,
+			    bi->bi_len, blk, new_state);
+
+	return bi->bi_start * GFS2_NBBY + blk;
+}
+
+/**
+ * rgblk_free - Change alloc state of given block(s)
+ * @sdp: the filesystem
+ * @bstart: the start of a run of blocks to free
+ * @blen: the length of the block run (all must lie within ONE RG!)
+ * @new_state: GFS2_BLKST_XXX the after-allocation block state
+ *
+ * Returns:  Resource group containing the block(s)
+ */
+
+static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
+				     u32 blen, unsigned char new_state)
+{
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_bitmap *bi = NULL;
+	u32 length, rgrp_blk, buf_blk;
+	unsigned int buf;
+
+	rgd = gfs2_blk2rgrpd(sdp, bstart);
+	if (!rgd) {
+		if (gfs2_consist(sdp))
+			fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
+		return NULL;
+	}
+
+	length = rgd->rd_ri.ri_length;
+
+	rgrp_blk = bstart - rgd->rd_ri.ri_data0;
+
+	while (blen--) {
+		for (buf = 0; buf < length; buf++) {
+			bi = rgd->rd_bits + buf;
+			if (rgrp_blk < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
+				break;
+		}
+
+		gfs2_assert(rgd->rd_sbd, buf < length);
+
+		buf_blk = rgrp_blk - bi->bi_start * GFS2_NBBY;
+		rgrp_blk++;
+
+		if (!bi->bi_clone) {
+			bi->bi_clone = kmalloc(bi->bi_bh->b_size,
+					       GFP_NOFS | __GFP_NOFAIL);
+			memcpy(bi->bi_clone + bi->bi_offset,
+			       bi->bi_bh->b_data + bi->bi_offset,
+			       bi->bi_len);
+		}
+		gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
+		gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+			    bi->bi_len, buf_blk, new_state);
+	}
+
+	return rgd;
+}
+
+/**
+ * gfs2_alloc_data - Allocate a data block
+ * @ip: the inode to allocate the data block for
+ *
+ * Returns: the allocated block
+ */
+
+u64 gfs2_alloc_data(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_rgrpd *rgd = al->al_rgd;
+	u32 goal, blk;
+	u64 block;
+
+	if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_data))
+		goal = ip->i_di.di_goal_data - rgd->rd_ri.ri_data0;
+	else
+		goal = rgd->rd_last_alloc_data;
+
+	blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
+	rgd->rd_last_alloc_data = blk;
+
+	block = rgd->rd_ri.ri_data0 + blk;
+	ip->i_di.di_goal_data = block;
+
+	gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
+	rgd->rd_rg.rg_free--;
+
+	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+	al->al_alloced++;
+
+	gfs2_statfs_change(sdp, 0, -1, 0);
+	gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid);
+
+	spin_lock(&sdp->sd_rindex_spin);
+	rgd->rd_free_clone--;
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	return block;
+}
+
+/**
+ * gfs2_alloc_meta - Allocate a metadata block
+ * @ip: the inode to allocate the metadata block for
+ *
+ * Returns: the allocated block
+ */
+
+u64 gfs2_alloc_meta(struct gfs2_inode *ip)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_alloc *al = &ip->i_alloc;
+	struct gfs2_rgrpd *rgd = al->al_rgd;
+	u32 goal, blk;
+	u64 block;
+
+	if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_meta))
+		goal = ip->i_di.di_goal_meta - rgd->rd_ri.ri_data0;
+	else
+		goal = rgd->rd_last_alloc_meta;
+
+	blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
+	rgd->rd_last_alloc_meta = blk;
+
+	block = rgd->rd_ri.ri_data0 + blk;
+	ip->i_di.di_goal_meta = block;
+
+	gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
+	rgd->rd_rg.rg_free--;
+
+	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+	al->al_alloced++;
+
+	gfs2_statfs_change(sdp, 0, -1, 0);
+	gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid);
+	gfs2_trans_add_unrevoke(sdp, block);
+
+	spin_lock(&sdp->sd_rindex_spin);
+	rgd->rd_free_clone--;
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	return block;
+}
+
+/**
+ * gfs2_alloc_di - Allocate a dinode
+ * @dip: the directory that the inode is going in
+ *
+ * Returns: the block allocated
+ */
+
+u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+	struct gfs2_alloc *al = &dip->i_alloc;
+	struct gfs2_rgrpd *rgd = al->al_rgd;
+	u32 blk;
+	u64 block;
+
+	blk = rgblk_search(rgd, rgd->rd_last_alloc_meta,
+			   GFS2_BLKST_FREE, GFS2_BLKST_DINODE);
+
+	rgd->rd_last_alloc_meta = blk;
+
+	block = rgd->rd_ri.ri_data0 + blk;
+
+	gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
+	rgd->rd_rg.rg_free--;
+	rgd->rd_rg.rg_dinodes++;
+	*generation = rgd->rd_rg.rg_igeneration++;
+	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+	al->al_alloced++;
+
+	gfs2_statfs_change(sdp, 0, -1, +1);
+	gfs2_trans_add_unrevoke(sdp, block);
+
+	spin_lock(&sdp->sd_rindex_spin);
+	rgd->rd_free_clone--;
+	spin_unlock(&sdp->sd_rindex_spin);
+
+	return block;
+}
+
+/**
+ * gfs2_free_data - free a contiguous run of data block(s)
+ * @ip: the inode these blocks are being freed from
+ * @bstart: first block of a run of contiguous blocks
+ * @blen: the length of the block run
+ *
+ */
+
+void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_rgrpd *rgd;
+
+	rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
+	if (!rgd)
+		return;
+
+	rgd->rd_rg.rg_free += blen;
+
+	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+	gfs2_trans_add_rg(rgd);
+
+	gfs2_statfs_change(sdp, 0, +blen, 0);
+	gfs2_quota_change(ip, -(s64)blen,
+			 ip->i_di.di_uid, ip->i_di.di_gid);
+}
+
+/**
+ * gfs2_free_meta - free a contiguous run of data block(s)
+ * @ip: the inode these blocks are being freed from
+ * @bstart: first block of a run of contiguous blocks
+ * @blen: the length of the block run
+ *
+ */
+
+void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	struct gfs2_rgrpd *rgd;
+
+	rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
+	if (!rgd)
+		return;
+
+	rgd->rd_rg.rg_free += blen;
+
+	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+	gfs2_trans_add_rg(rgd);
+
+	gfs2_statfs_change(sdp, 0, +blen, 0);
+	gfs2_quota_change(ip, -(s64)blen, ip->i_di.di_uid, ip->i_di.di_gid);
+	gfs2_meta_wipe(ip, bstart, blen);
+}
+
+void gfs2_unlink_di(struct inode *inode)
+{
+	struct gfs2_inode *ip = GFS2_I(inode);
+	struct gfs2_sbd *sdp = GFS2_SB(inode);
+	struct gfs2_rgrpd *rgd;
+	u64 blkno = ip->i_num.no_addr;
+
+	rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_UNLINKED);
+	if (!rgd)
+		return;
+	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+	gfs2_trans_add_rg(rgd);
+}
+
+static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	struct gfs2_rgrpd *tmp_rgd;
+
+	tmp_rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_FREE);
+	if (!tmp_rgd)
+		return;
+	gfs2_assert_withdraw(sdp, rgd == tmp_rgd);
+
+	if (!rgd->rd_rg.rg_dinodes)
+		gfs2_consist_rgrpd(rgd);
+	rgd->rd_rg.rg_dinodes--;
+	rgd->rd_rg.rg_free++;
+
+	gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+	gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+	gfs2_statfs_change(sdp, 0, +1, -1);
+	gfs2_trans_add_rg(rgd);
+}
+
+
+void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
+{
+	gfs2_free_uninit_di(rgd, ip->i_num.no_addr);
+	gfs2_quota_change(ip, -1, ip->i_di.di_uid, ip->i_di.di_gid);
+	gfs2_meta_wipe(ip, ip->i_num.no_addr, 1);
+}
+
+/**
+ * gfs2_rlist_add - add a RG to a list of RGs
+ * @sdp: the filesystem
+ * @rlist: the list of resource groups
+ * @block: the block
+ *
+ * Figure out what RG a block belongs to and add that RG to the list
+ *
+ * FIXME: Don't use NOFAIL
+ *
+ */
+
+void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
+		    u64 block)
+{
+	struct gfs2_rgrpd *rgd;
+	struct gfs2_rgrpd **tmp;
+	unsigned int new_space;
+	unsigned int x;
+
+	if (gfs2_assert_warn(sdp, !rlist->rl_ghs))
+		return;
+
+	rgd = gfs2_blk2rgrpd(sdp, block);
+	if (!rgd) {
+		if (gfs2_consist(sdp))
+			fs_err(sdp, "block = %llu\n", (unsigned long long)block);
+		return;
+	}
+
+	for (x = 0; x < rlist->rl_rgrps; x++)
+		if (rlist->rl_rgd[x] == rgd)
+			return;
+
+	if (rlist->rl_rgrps == rlist->rl_space) {
+		new_space = rlist->rl_space + 10;
+
+		tmp = kcalloc(new_space, sizeof(struct gfs2_rgrpd *),
+			      GFP_NOFS | __GFP_NOFAIL);
+
+		if (rlist->rl_rgd) {
+			memcpy(tmp, rlist->rl_rgd,
+			       rlist->rl_space * sizeof(struct gfs2_rgrpd *));
+			kfree(rlist->rl_rgd);
+		}
+
+		rlist->rl_space = new_space;
+		rlist->rl_rgd = tmp;
+	}
+
+	rlist->rl_rgd[rlist->rl_rgrps++] = rgd;
+}
+
+/**
+ * gfs2_rlist_alloc - all RGs have been added to the rlist, now allocate
+ *      and initialize an array of glock holders for them
+ * @rlist: the list of resource groups
+ * @state: the lock state to acquire the RG lock in
+ * @flags: the modifier flags for the holder structures
+ *
+ * FIXME: Don't use NOFAIL
+ *
+ */
+
+void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state,
+		      int flags)
+{
+	unsigned int x;
+
+	rlist->rl_ghs = kcalloc(rlist->rl_rgrps, sizeof(struct gfs2_holder),
+				GFP_NOFS | __GFP_NOFAIL);
+	for (x = 0; x < rlist->rl_rgrps; x++)
+		gfs2_holder_init(rlist->rl_rgd[x]->rd_gl,
+				state, flags,
+				&rlist->rl_ghs[x]);
+}
+
+/**
+ * gfs2_rlist_free - free a resource group list
+ * @list: the list of resource groups
+ *
+ */
+
+void gfs2_rlist_free(struct gfs2_rgrp_list *rlist)
+{
+	unsigned int x;
+
+	kfree(rlist->rl_rgd);
+
+	if (rlist->rl_ghs) {
+		for (x = 0; x < rlist->rl_rgrps; x++)
+			gfs2_holder_uninit(&rlist->rl_ghs[x]);
+		kfree(rlist->rl_ghs);
+	}
+}
+
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
new file mode 100644
index 0000000..9eedfd1
--- /dev/null
+++ b/fs/gfs2/rgrp.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __RGRP_DOT_H__
+#define __RGRP_DOT_H__
+
+struct gfs2_rgrpd;
+struct gfs2_sbd;
+struct gfs2_holder;
+
+void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
+
+struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
+struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
+struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
+
+void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
+int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
+
+int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
+void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
+void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
+
+void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
+
+struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
+static inline void gfs2_alloc_put(struct gfs2_inode *ip)
+{
+	return; /* Se we can see where ip->i_alloc is used */
+}
+
+int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
+			 char *file, unsigned int line);
+#define gfs2_inplace_reserve(ip) \
+gfs2_inplace_reserve_i((ip), __FILE__, __LINE__)
+
+void gfs2_inplace_release(struct gfs2_inode *ip);
+
+unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
+
+u64 gfs2_alloc_data(struct gfs2_inode *ip);
+u64 gfs2_alloc_meta(struct gfs2_inode *ip);
+u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
+
+void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
+void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
+void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
+void gfs2_unlink_di(struct inode *inode);
+
+struct gfs2_rgrp_list {
+	unsigned int rl_rgrps;
+	unsigned int rl_space;
+	struct gfs2_rgrpd **rl_rgd;
+	struct gfs2_holder *rl_ghs;
+};
+
+void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
+		    u64 block);
+void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state,
+		      int flags);
+void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
+
+#endif /* __RGRP_DOT_H__ */
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
new file mode 100644
index 0000000..6a78b1b
--- /dev/null
+++ b/fs/gfs2/super.c
@@ -0,0 +1,976 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/crc32.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/bio.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "dir.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "super.h"
+#include "trans.h"
+#include "util.h"
+
+static const u32 gfs2_old_fs_formats[] = {
+        0
+};
+
+static const u32 gfs2_old_multihost_formats[] = {
+        0
+};
+
+/**
+ * gfs2_tune_init - Fill a gfs2_tune structure with default values
+ * @gt: tune
+ *
+ */
+
+void gfs2_tune_init(struct gfs2_tune *gt)
+{
+	spin_lock_init(&gt->gt_spin);
+
+	gt->gt_ilimit = 100;
+	gt->gt_ilimit_tries = 3;
+	gt->gt_ilimit_min = 1;
+	gt->gt_demote_secs = 300;
+	gt->gt_incore_log_blocks = 1024;
+	gt->gt_log_flush_secs = 60;
+	gt->gt_jindex_refresh_secs = 60;
+	gt->gt_scand_secs = 15;
+	gt->gt_recoverd_secs = 60;
+	gt->gt_logd_secs = 1;
+	gt->gt_quotad_secs = 5;
+	gt->gt_quota_simul_sync = 64;
+	gt->gt_quota_warn_period = 10;
+	gt->gt_quota_scale_num = 1;
+	gt->gt_quota_scale_den = 1;
+	gt->gt_quota_cache_secs = 300;
+	gt->gt_quota_quantum = 60;
+	gt->gt_atime_quantum = 3600;
+	gt->gt_new_files_jdata = 0;
+	gt->gt_new_files_directio = 0;
+	gt->gt_max_atomic_write = 4 << 20;
+	gt->gt_max_readahead = 1 << 18;
+	gt->gt_lockdump_size = 131072;
+	gt->gt_stall_secs = 600;
+	gt->gt_complain_secs = 10;
+	gt->gt_reclaim_limit = 5000;
+	gt->gt_entries_per_readdir = 32;
+	gt->gt_prefetch_secs = 10;
+	gt->gt_greedy_default = HZ / 10;
+	gt->gt_greedy_quantum = HZ / 40;
+	gt->gt_greedy_max = HZ / 4;
+	gt->gt_statfs_quantum = 30;
+	gt->gt_statfs_slow = 0;
+}
+
+/**
+ * gfs2_check_sb - Check superblock
+ * @sdp: the filesystem
+ * @sb: The superblock
+ * @silent: Don't print a message if the check fails
+ *
+ * Checks the version code of the FS is one that we understand how to
+ * read and that the sizes of the various on-disk structures have not
+ * changed.
+ */
+
+int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent)
+{
+	unsigned int x;
+
+	if (sb->sb_header.mh_magic != GFS2_MAGIC ||
+	    sb->sb_header.mh_type != GFS2_METATYPE_SB) {
+		if (!silent)
+			printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n");
+		return -EINVAL;
+	}
+
+	/*  If format numbers match exactly, we're done.  */
+
+	if (sb->sb_fs_format == GFS2_FORMAT_FS &&
+	    sb->sb_multihost_format == GFS2_FORMAT_MULTI)
+		return 0;
+
+	if (sb->sb_fs_format != GFS2_FORMAT_FS) {
+		for (x = 0; gfs2_old_fs_formats[x]; x++)
+			if (gfs2_old_fs_formats[x] == sb->sb_fs_format)
+				break;
+
+		if (!gfs2_old_fs_formats[x]) {
+			printk(KERN_WARNING
+			       "GFS2: code version (%u, %u) is incompatible "
+			       "with ondisk format (%u, %u)\n",
+			       GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
+			       sb->sb_fs_format, sb->sb_multihost_format);
+			printk(KERN_WARNING
+			       "GFS2: I don't know how to upgrade this FS\n");
+			return -EINVAL;
+		}
+	}
+
+	if (sb->sb_multihost_format != GFS2_FORMAT_MULTI) {
+		for (x = 0; gfs2_old_multihost_formats[x]; x++)
+			if (gfs2_old_multihost_formats[x] ==
+			    sb->sb_multihost_format)
+				break;
+
+		if (!gfs2_old_multihost_formats[x]) {
+			printk(KERN_WARNING
+			       "GFS2: code version (%u, %u) is incompatible "
+			       "with ondisk format (%u, %u)\n",
+			       GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
+			       sb->sb_fs_format, sb->sb_multihost_format);
+			printk(KERN_WARNING
+			       "GFS2: I don't know how to upgrade this FS\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!sdp->sd_args.ar_upgrade) {
+		printk(KERN_WARNING
+		       "GFS2: code version (%u, %u) is incompatible "
+		       "with ondisk format (%u, %u)\n",
+		       GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
+		       sb->sb_fs_format, sb->sb_multihost_format);
+		printk(KERN_INFO
+		       "GFS2: Use the \"upgrade\" mount option to upgrade "
+		       "the FS\n");
+		printk(KERN_INFO "GFS2: See the manual for more details\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error)
+{
+	struct page *page = bio->bi_private;
+	if (bio->bi_size)
+		return 1;
+
+	if (!error)
+		SetPageUptodate(page);
+	else
+		printk(KERN_WARNING "gfs2: error %d reading superblock\n", error);
+	unlock_page(page);
+	return 0;
+}
+
+struct page *gfs2_read_super(struct super_block *sb, sector_t sector)
+{
+	struct page *page;
+	struct bio *bio;
+
+	page = alloc_page(GFP_KERNEL);
+	if (unlikely(!page))
+		return NULL;
+
+	ClearPageUptodate(page);
+	ClearPageDirty(page);
+	lock_page(page);
+
+	bio = bio_alloc(GFP_KERNEL, 1);
+	if (unlikely(!bio)) {
+		__free_page(page);
+		return NULL;
+	}
+
+	bio->bi_sector = sector;
+	bio->bi_bdev = sb->s_bdev;
+	bio_add_page(bio, page, PAGE_SIZE, 0);
+
+	bio->bi_end_io = end_bio_io_page;
+	bio->bi_private = page;
+	submit_bio(READ_SYNC | (1 << BIO_RW_META), bio);
+	wait_on_page_locked(page);
+	bio_put(bio);
+	if (!PageUptodate(page)) {
+		__free_page(page);
+		return NULL;
+	}
+	return page;
+}
+
+/**
+ * gfs2_read_sb - Read super block
+ * @sdp: The GFS2 superblock
+ * @gl: the glock for the superblock (assumed to be held)
+ * @silent: Don't print message if mount fails
+ *
+ */
+
+int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent)
+{
+	u32 hash_blocks, ind_blocks, leaf_blocks;
+	u32 tmp_blocks;
+	unsigned int x;
+	int error;
+	struct page *page;
+	char *sb;
+
+	page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
+	if (!page) {
+		if (!silent)
+			fs_err(sdp, "can't read superblock\n");
+		return -EIO;
+	}
+	sb = kmap(page);
+	gfs2_sb_in(&sdp->sd_sb, sb);
+	kunmap(page);
+	__free_page(page);
+
+	error = gfs2_check_sb(sdp, &sdp->sd_sb, silent);
+	if (error)
+		return error;
+
+	sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
+			       GFS2_BASIC_BLOCK_SHIFT;
+	sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
+	sdp->sd_diptrs = (sdp->sd_sb.sb_bsize -
+			  sizeof(struct gfs2_dinode)) / sizeof(u64);
+	sdp->sd_inptrs = (sdp->sd_sb.sb_bsize -
+			  sizeof(struct gfs2_meta_header)) / sizeof(u64);
+	sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
+	sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2;
+	sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1;
+	sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(u64);
+	sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize -
+				sizeof(struct gfs2_meta_header)) /
+			        sizeof(struct gfs2_quota_change);
+
+	/* Compute maximum reservation required to add a entry to a directory */
+
+	hash_blocks = DIV_ROUND_UP(sizeof(u64) * (1 << GFS2_DIR_MAX_DEPTH),
+			     sdp->sd_jbsize);
+
+	ind_blocks = 0;
+	for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) {
+		tmp_blocks = DIV_ROUND_UP(tmp_blocks, sdp->sd_inptrs);
+		ind_blocks += tmp_blocks;
+	}
+
+	leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH;
+
+	sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks;
+
+	sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize -
+				sizeof(struct gfs2_dinode);
+	sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs;
+	for (x = 2;; x++) {
+		u64 space, d;
+		u32 m;
+
+		space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs;
+		d = space;
+		m = do_div(d, sdp->sd_inptrs);
+
+		if (d != sdp->sd_heightsize[x - 1] || m)
+			break;
+		sdp->sd_heightsize[x] = space;
+	}
+	sdp->sd_max_height = x;
+	gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT);
+
+	sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize -
+				 sizeof(struct gfs2_dinode);
+	sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
+	for (x = 2;; x++) {
+		u64 space, d;
+		u32 m;
+
+		space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs;
+		d = space;
+		m = do_div(d, sdp->sd_inptrs);
+
+		if (d != sdp->sd_jheightsize[x - 1] || m)
+			break;
+		sdp->sd_jheightsize[x] = space;
+	}
+	sdp->sd_max_jheight = x;
+	gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
+
+	return 0;
+}
+
+/**
+ * gfs2_jindex_hold - Grab a lock on the jindex
+ * @sdp: The GFS2 superblock
+ * @ji_gh: the holder for the jindex glock
+ *
+ * This is very similar to the gfs2_rindex_hold() function, except that
+ * in general we hold the jindex lock for longer periods of time and
+ * we grab it far less frequently (in general) then the rgrp lock.
+ *
+ * Returns: errno
+ */
+
+int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
+{
+	struct gfs2_inode *dip = GFS2_I(sdp->sd_jindex);
+	struct qstr name;
+	char buf[20];
+	struct gfs2_jdesc *jd;
+	int error;
+
+	name.name = buf;
+
+	mutex_lock(&sdp->sd_jindex_mutex);
+
+	for (;;) {
+		error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
+					   GL_LOCAL_EXCL, ji_gh);
+		if (error)
+			break;
+
+		name.len = sprintf(buf, "journal%u", sdp->sd_journals);
+		name.hash = gfs2_disk_hash(name.name, name.len);
+
+		error = gfs2_dir_search(sdp->sd_jindex, &name, NULL, NULL);
+		if (error == -ENOENT) {
+			error = 0;
+			break;
+		}
+
+		gfs2_glock_dq_uninit(ji_gh);
+
+		if (error)
+			break;
+
+		error = -ENOMEM;
+		jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL);
+		if (!jd)
+			break;
+
+		jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
+		if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
+			if (!jd->jd_inode)
+				error = -ENOENT;
+			else
+				error = PTR_ERR(jd->jd_inode);
+			kfree(jd);
+			break;
+		}
+
+		spin_lock(&sdp->sd_jindex_spin);
+		jd->jd_jid = sdp->sd_journals++;
+		list_add_tail(&jd->jd_list, &sdp->sd_jindex_list);
+		spin_unlock(&sdp->sd_jindex_spin);
+	}
+
+	mutex_unlock(&sdp->sd_jindex_mutex);
+
+	return error;
+}
+
+/**
+ * gfs2_jindex_free - Clear all the journal index information
+ * @sdp: The GFS2 superblock
+ *
+ */
+
+void gfs2_jindex_free(struct gfs2_sbd *sdp)
+{
+	struct list_head list;
+	struct gfs2_jdesc *jd;
+
+	spin_lock(&sdp->sd_jindex_spin);
+	list_add(&list, &sdp->sd_jindex_list);
+	list_del_init(&sdp->sd_jindex_list);
+	sdp->sd_journals = 0;
+	spin_unlock(&sdp->sd_jindex_spin);
+
+	while (!list_empty(&list)) {
+		jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
+		list_del(&jd->jd_list);
+		iput(jd->jd_inode);
+		kfree(jd);
+	}
+}
+
+static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid)
+{
+	struct gfs2_jdesc *jd;
+	int found = 0;
+
+	list_for_each_entry(jd, head, jd_list) {
+		if (jd->jd_jid == jid) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)
+		jd = NULL;
+
+	return jd;
+}
+
+struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid)
+{
+	struct gfs2_jdesc *jd;
+
+	spin_lock(&sdp->sd_jindex_spin);
+	jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
+	spin_unlock(&sdp->sd_jindex_spin);
+
+	return jd;
+}
+
+void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid)
+{
+	struct gfs2_jdesc *jd;
+
+	spin_lock(&sdp->sd_jindex_spin);
+	jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
+	if (jd)
+		jd->jd_dirty = 1;
+	spin_unlock(&sdp->sd_jindex_spin);
+}
+
+struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp)
+{
+	struct gfs2_jdesc *jd;
+	int found = 0;
+
+	spin_lock(&sdp->sd_jindex_spin);
+
+	list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+		if (jd->jd_dirty) {
+			jd->jd_dirty = 0;
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock(&sdp->sd_jindex_spin);
+
+	if (!found)
+		jd = NULL;
+
+	return jd;
+}
+
+int gfs2_jdesc_check(struct gfs2_jdesc *jd)
+{
+	struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+	struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+	int ar;
+	int error;
+
+	if (ip->i_di.di_size < (8 << 20) || ip->i_di.di_size > (1 << 30) ||
+	    (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) {
+		gfs2_consist_inode(ip);
+		return -EIO;
+	}
+	jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift;
+
+	error = gfs2_write_alloc_required(ip, 0, ip->i_di.di_size, &ar);
+	if (!error && ar) {
+		gfs2_consist_inode(ip);
+		error = -EIO;
+	}
+
+	return error;
+}
+
+/**
+ * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one
+ * @sdp: the filesystem
+ *
+ * Returns: errno
+ */
+
+int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
+{
+	struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
+	struct gfs2_glock *j_gl = ip->i_gl;
+	struct gfs2_holder t_gh;
+	struct gfs2_log_header head;
+	int error;
+
+	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
+				   GL_LOCAL_EXCL, &t_gh);
+	if (error)
+		return error;
+
+	gfs2_meta_cache_flush(ip);
+	j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
+
+	error = gfs2_find_jhead(sdp->sd_jdesc, &head);
+	if (error)
+		goto fail;
+
+	if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
+		gfs2_consist(sdp);
+		error = -EIO;
+		goto fail;
+	}
+
+	/*  Initialize some head of the log stuff  */
+	sdp->sd_log_sequence = head.lh_sequence + 1;
+	gfs2_log_pointers_init(sdp, head.lh_blkno);
+
+	error = gfs2_quota_init(sdp);
+	if (error)
+		goto fail;
+
+	set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+
+	gfs2_glock_dq_uninit(&t_gh);
+
+	return 0;
+
+fail:
+	t_gh.gh_flags |= GL_NOCACHE;
+	gfs2_glock_dq_uninit(&t_gh);
+
+	return error;
+}
+
+/**
+ * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
+ * @sdp: the filesystem
+ *
+ * Returns: errno
+ */
+
+int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
+{
+	struct gfs2_holder t_gh;
+	int error;
+
+	gfs2_quota_sync(sdp);
+	gfs2_statfs_sync(sdp);
+
+	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
+				GL_LOCAL_EXCL | GL_NOCACHE,
+				&t_gh);
+	if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+		return error;
+
+	gfs2_meta_syncfs(sdp);
+	gfs2_log_shutdown(sdp);
+
+	clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+
+	if (t_gh.gh_gl)
+		gfs2_glock_dq_uninit(&t_gh);
+
+	gfs2_quota_cleanup(sdp);
+
+	return error;
+}
+
+int gfs2_statfs_init(struct gfs2_sbd *sdp)
+{
+	struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
+	struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
+	struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
+	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+	struct buffer_head *m_bh, *l_bh;
+	struct gfs2_holder gh;
+	int error;
+
+	error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
+				   &gh);
+	if (error)
+		return error;
+
+	error = gfs2_meta_inode_buffer(m_ip, &m_bh);
+	if (error)
+		goto out;
+
+	if (sdp->sd_args.ar_spectator) {
+		spin_lock(&sdp->sd_statfs_spin);
+		gfs2_statfs_change_in(m_sc, m_bh->b_data +
+				      sizeof(struct gfs2_dinode));
+		spin_unlock(&sdp->sd_statfs_spin);
+	} else {
+		error = gfs2_meta_inode_buffer(l_ip, &l_bh);
+		if (error)
+			goto out_m_bh;
+
+		spin_lock(&sdp->sd_statfs_spin);
+		gfs2_statfs_change_in(m_sc, m_bh->b_data +
+				      sizeof(struct gfs2_dinode));
+		gfs2_statfs_change_in(l_sc, l_bh->b_data +
+				      sizeof(struct gfs2_dinode));
+		spin_unlock(&sdp->sd_statfs_spin);
+
+		brelse(l_bh);
+	}
+
+out_m_bh:
+	brelse(m_bh);
+out:
+	gfs2_glock_dq_uninit(&gh);
+	return 0;
+}
+
+void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
+			s64 dinodes)
+{
+	struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
+	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+	struct buffer_head *l_bh;
+	int error;
+
+	error = gfs2_meta_inode_buffer(l_ip, &l_bh);
+	if (error)
+		return;
+
+	mutex_lock(&sdp->sd_statfs_mutex);
+	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+	mutex_unlock(&sdp->sd_statfs_mutex);
+
+	spin_lock(&sdp->sd_statfs_spin);
+	l_sc->sc_total += total;
+	l_sc->sc_free += free;
+	l_sc->sc_dinodes += dinodes;
+	gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode));
+	spin_unlock(&sdp->sd_statfs_spin);
+
+	brelse(l_bh);
+}
+
+int gfs2_statfs_sync(struct gfs2_sbd *sdp)
+{
+	struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
+	struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
+	struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
+	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+	struct gfs2_holder gh;
+	struct buffer_head *m_bh, *l_bh;
+	int error;
+
+	error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
+				   &gh);
+	if (error)
+		return error;
+
+	error = gfs2_meta_inode_buffer(m_ip, &m_bh);
+	if (error)
+		goto out;
+
+	spin_lock(&sdp->sd_statfs_spin);
+	gfs2_statfs_change_in(m_sc, m_bh->b_data +
+			      sizeof(struct gfs2_dinode));
+	if (!l_sc->sc_total && !l_sc->sc_free && !l_sc->sc_dinodes) {
+		spin_unlock(&sdp->sd_statfs_spin);
+		goto out_bh;
+	}
+	spin_unlock(&sdp->sd_statfs_spin);
+
+	error = gfs2_meta_inode_buffer(l_ip, &l_bh);
+	if (error)
+		goto out_bh;
+
+	error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
+	if (error)
+		goto out_bh2;
+
+	mutex_lock(&sdp->sd_statfs_mutex);
+	gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+	mutex_unlock(&sdp->sd_statfs_mutex);
+
+	spin_lock(&sdp->sd_statfs_spin);
+	m_sc->sc_total += l_sc->sc_total;
+	m_sc->sc_free += l_sc->sc_free;
+	m_sc->sc_dinodes += l_sc->sc_dinodes;
+	memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
+	memset(l_bh->b_data + sizeof(struct gfs2_dinode),
+	       0, sizeof(struct gfs2_statfs_change));
+	spin_unlock(&sdp->sd_statfs_spin);
+
+	gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
+	gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
+
+	gfs2_trans_end(sdp);
+
+out_bh2:
+	brelse(l_bh);
+out_bh:
+	brelse(m_bh);
+out:
+	gfs2_glock_dq_uninit(&gh);
+	return error;
+}
+
+/**
+ * gfs2_statfs_i - Do a statfs
+ * @sdp: the filesystem
+ * @sg: the sg structure
+ *
+ * Returns: errno
+ */
+
+int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
+{
+	struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
+	struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+
+	spin_lock(&sdp->sd_statfs_spin);
+
+	*sc = *m_sc;
+	sc->sc_total += l_sc->sc_total;
+	sc->sc_free += l_sc->sc_free;
+	sc->sc_dinodes += l_sc->sc_dinodes;
+
+	spin_unlock(&sdp->sd_statfs_spin);
+
+	if (sc->sc_free < 0)
+		sc->sc_free = 0;
+	if (sc->sc_free > sc->sc_total)
+		sc->sc_free = sc->sc_total;
+	if (sc->sc_dinodes < 0)
+		sc->sc_dinodes = 0;
+
+	return 0;
+}
+
+/**
+ * statfs_fill - fill in the sg for a given RG
+ * @rgd: the RG
+ * @sc: the sc structure
+ *
+ * Returns: 0 on success, -ESTALE if the LVB is invalid
+ */
+
+static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
+			    struct gfs2_statfs_change *sc)
+{
+	gfs2_rgrp_verify(rgd);
+	sc->sc_total += rgd->rd_ri.ri_data;
+	sc->sc_free += rgd->rd_rg.rg_free;
+	sc->sc_dinodes += rgd->rd_rg.rg_dinodes;
+	return 0;
+}
+
+/**
+ * gfs2_statfs_slow - Stat a filesystem using asynchronous locking
+ * @sdp: the filesystem
+ * @sc: the sc info that will be returned
+ *
+ * Any error (other than a signal) will cause this routine to fall back
+ * to the synchronous version.
+ *
+ * FIXME: This really shouldn't busy wait like this.
+ *
+ * Returns: errno
+ */
+
+int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
+{
+	struct gfs2_holder ri_gh;
+	struct gfs2_rgrpd *rgd_next;
+	struct gfs2_holder *gha, *gh;
+	unsigned int slots = 64;
+	unsigned int x;
+	int done;
+	int error = 0, err;
+
+	memset(sc, 0, sizeof(struct gfs2_statfs_change));
+	gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL);
+	if (!gha)
+		return -ENOMEM;
+
+	error = gfs2_rindex_hold(sdp, &ri_gh);
+	if (error)
+		goto out;
+
+	rgd_next = gfs2_rgrpd_get_first(sdp);
+
+	for (;;) {
+		done = 1;
+
+		for (x = 0; x < slots; x++) {
+			gh = gha + x;
+
+			if (gh->gh_gl && gfs2_glock_poll(gh)) {
+				err = gfs2_glock_wait(gh);
+				if (err) {
+					gfs2_holder_uninit(gh);
+					error = err;
+				} else {
+					if (!error)
+						error = statfs_slow_fill(
+							gh->gh_gl->gl_object, sc);
+					gfs2_glock_dq_uninit(gh);
+				}
+			}
+
+			if (gh->gh_gl)
+				done = 0;
+			else if (rgd_next && !error) {
+				error = gfs2_glock_nq_init(rgd_next->rd_gl,
+							   LM_ST_SHARED,
+							   GL_ASYNC,
+							   gh);
+				rgd_next = gfs2_rgrpd_get_next(rgd_next);
+				done = 0;
+			}
+
+			if (signal_pending(current))
+				error = -ERESTARTSYS;
+		}
+
+		if (done)
+			break;
+
+		yield();
+	}
+
+	gfs2_glock_dq_uninit(&ri_gh);
+
+out:
+	kfree(gha);
+	return error;
+}
+
+struct lfcc {
+	struct list_head list;
+	struct gfs2_holder gh;
+};
+
+/**
+ * gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all
+ *                            journals are clean
+ * @sdp: the file system
+ * @state: the state to put the transaction lock into
+ * @t_gh: the hold on the transaction lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
+				    struct gfs2_holder *t_gh)
+{
+	struct gfs2_inode *ip;
+	struct gfs2_holder ji_gh;
+	struct gfs2_jdesc *jd;
+	struct lfcc *lfcc;
+	LIST_HEAD(list);
+	struct gfs2_log_header lh;
+	int error;
+
+	error = gfs2_jindex_hold(sdp, &ji_gh);
+	if (error)
+		return error;
+
+	list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+		lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
+		if (!lfcc) {
+			error = -ENOMEM;
+			goto out;
+		}
+		ip = GFS2_I(jd->jd_inode);
+		error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &lfcc->gh);
+		if (error) {
+			kfree(lfcc);
+			goto out;
+		}
+		list_add(&lfcc->list, &list);
+	}
+
+	error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED,
+			       LM_FLAG_PRIORITY | GL_NOCACHE,
+			       t_gh);
+
+	list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+		error = gfs2_jdesc_check(jd);
+		if (error)
+			break;
+		error = gfs2_find_jhead(jd, &lh);
+		if (error)
+			break;
+		if (!(lh.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
+			error = -EBUSY;
+			break;
+		}
+	}
+
+	if (error)
+		gfs2_glock_dq_uninit(t_gh);
+
+out:
+	while (!list_empty(&list)) {
+		lfcc = list_entry(list.next, struct lfcc, list);
+		list_del(&lfcc->list);
+		gfs2_glock_dq_uninit(&lfcc->gh);
+		kfree(lfcc);
+	}
+	gfs2_glock_dq_uninit(&ji_gh);
+	return error;
+}
+
+/**
+ * gfs2_freeze_fs - freezes the file system
+ * @sdp: the file system
+ *
+ * This function flushes data and meta data for all machines by
+ * aquiring the transaction log exclusively.  All journals are
+ * ensured to be in a clean state as well.
+ *
+ * Returns: errno
+ */
+
+int gfs2_freeze_fs(struct gfs2_sbd *sdp)
+{
+	int error = 0;
+
+	mutex_lock(&sdp->sd_freeze_lock);
+
+	if (!sdp->sd_freeze_count++) {
+		error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
+		if (error)
+			sdp->sd_freeze_count--;
+	}
+
+	mutex_unlock(&sdp->sd_freeze_lock);
+
+	return error;
+}
+
+/**
+ * gfs2_unfreeze_fs - unfreezes the file system
+ * @sdp: the file system
+ *
+ * This function allows the file system to proceed by unlocking
+ * the exclusively held transaction lock.  Other GFS2 nodes are
+ * now free to acquire the lock shared and go on with their lives.
+ *
+ */
+
+void gfs2_unfreeze_fs(struct gfs2_sbd *sdp)
+{
+	mutex_lock(&sdp->sd_freeze_lock);
+
+	if (sdp->sd_freeze_count && !--sdp->sd_freeze_count)
+		gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
+
+	mutex_unlock(&sdp->sd_freeze_lock);
+}
+
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
new file mode 100644
index 0000000..5bb443a
--- /dev/null
+++ b/fs/gfs2/super.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __SUPER_DOT_H__
+#define __SUPER_DOT_H__
+
+#include "incore.h"
+
+void gfs2_tune_init(struct gfs2_tune *gt);
+
+int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent);
+int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent);
+struct page *gfs2_read_super(struct super_block *sb, sector_t sector);
+
+static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
+{
+	unsigned int x;
+	spin_lock(&sdp->sd_jindex_spin);
+	x = sdp->sd_journals;
+	spin_unlock(&sdp->sd_jindex_spin);
+	return x;
+}
+
+int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh);
+void gfs2_jindex_free(struct gfs2_sbd *sdp);
+
+struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
+void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid);
+struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp);
+int gfs2_jdesc_check(struct gfs2_jdesc *jd);
+
+int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
+			      struct gfs2_inode **ipp);
+
+int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
+int gfs2_make_fs_ro(struct gfs2_sbd *sdp);
+
+int gfs2_statfs_init(struct gfs2_sbd *sdp);
+void gfs2_statfs_change(struct gfs2_sbd *sdp,
+			s64 total, s64 free, s64 dinodes);
+int gfs2_statfs_sync(struct gfs2_sbd *sdp);
+int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc);
+int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc);
+
+int gfs2_freeze_fs(struct gfs2_sbd *sdp);
+void gfs2_unfreeze_fs(struct gfs2_sbd *sdp);
+
+#endif /* __SUPER_DOT_H__ */
+
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
new file mode 100644
index 0000000..0e0ec98
--- /dev/null
+++ b/fs/gfs2/sys.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "lm.h"
+#include "sys.h"
+#include "super.h"
+#include "glock.h"
+#include "quota.h"
+#include "util.h"
+
+char *gfs2_sys_margs;
+spinlock_t gfs2_sys_margs_lock;
+
+static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_vfs->s_id);
+}
+
+static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_fsname);
+}
+
+static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
+{
+	unsigned int count;
+
+	mutex_lock(&sdp->sd_freeze_lock);
+	count = sdp->sd_freeze_count;
+	mutex_unlock(&sdp->sd_freeze_lock);
+
+	return snprintf(buf, PAGE_SIZE, "%u\n", count);
+}
+
+static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+	ssize_t ret = len;
+	int error = 0;
+	int n = simple_strtol(buf, NULL, 0);
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	switch (n) {
+	case 0:
+		gfs2_unfreeze_fs(sdp);
+		break;
+	case 1:
+		error = gfs2_freeze_fs(sdp);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (error)
+		fs_warn(sdp, "freeze %d error %d", n, error);
+
+	return ret;
+}
+
+static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
+{
+	unsigned int b = test_bit(SDF_SHUTDOWN, &sdp->sd_flags);
+	return snprintf(buf, PAGE_SIZE, "%u\n", b);
+}
+
+static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (simple_strtol(buf, NULL, 0) != 1)
+		return -EINVAL;
+
+	gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: withdrawing from cluster at user's request\n",
+		sdp->sd_fsname);
+	return len;
+}
+
+static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,
+				 size_t len)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (simple_strtol(buf, NULL, 0) != 1)
+		return -EINVAL;
+
+	gfs2_statfs_sync(sdp);
+	return len;
+}
+
+static ssize_t shrink_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (simple_strtol(buf, NULL, 0) != 1)
+		return -EINVAL;
+
+	gfs2_gl_hash_clear(sdp, NO_WAIT);
+	return len;
+}
+
+static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
+				size_t len)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (simple_strtol(buf, NULL, 0) != 1)
+		return -EINVAL;
+
+	gfs2_quota_sync(sdp);
+	return len;
+}
+
+static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,
+					size_t len)
+{
+	u32 id;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	id = simple_strtoul(buf, NULL, 0);
+
+	gfs2_quota_refresh(sdp, 1, id);
+	return len;
+}
+
+static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
+					 size_t len)
+{
+	u32 id;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	id = simple_strtoul(buf, NULL, 0);
+
+	gfs2_quota_refresh(sdp, 0, id);
+	return len;
+}
+
+struct gfs2_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct gfs2_sbd *, char *);
+	ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
+};
+
+#define GFS2_ATTR(name, mode, show, store) \
+static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store)
+
+GFS2_ATTR(id,                  0444, id_show,       NULL);
+GFS2_ATTR(fsname,              0444, fsname_show,   NULL);
+GFS2_ATTR(freeze,              0644, freeze_show,   freeze_store);
+GFS2_ATTR(shrink,              0200, NULL,          shrink_store);
+GFS2_ATTR(withdraw,            0644, withdraw_show, withdraw_store);
+GFS2_ATTR(statfs_sync,         0200, NULL,          statfs_sync_store);
+GFS2_ATTR(quota_sync,          0200, NULL,          quota_sync_store);
+GFS2_ATTR(quota_refresh_user,  0200, NULL,          quota_refresh_user_store);
+GFS2_ATTR(quota_refresh_group, 0200, NULL,          quota_refresh_group_store);
+
+static struct attribute *gfs2_attrs[] = {
+	&gfs2_attr_id.attr,
+	&gfs2_attr_fsname.attr,
+	&gfs2_attr_freeze.attr,
+	&gfs2_attr_shrink.attr,
+	&gfs2_attr_withdraw.attr,
+	&gfs2_attr_statfs_sync.attr,
+	&gfs2_attr_quota_sync.attr,
+	&gfs2_attr_quota_refresh_user.attr,
+	&gfs2_attr_quota_refresh_group.attr,
+	NULL,
+};
+
+static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr,
+			      char *buf)
+{
+	struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+	struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
+	return a->show ? a->show(sdp, buf) : 0;
+}
+
+static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr,
+			       const char *buf, size_t len)
+{
+	struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+	struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
+	return a->store ? a->store(sdp, buf, len) : len;
+}
+
+static struct sysfs_ops gfs2_attr_ops = {
+	.show  = gfs2_attr_show,
+	.store = gfs2_attr_store,
+};
+
+static struct kobj_type gfs2_ktype = {
+	.default_attrs = gfs2_attrs,
+	.sysfs_ops     = &gfs2_attr_ops,
+};
+
+static struct kset gfs2_kset = {
+	.subsys = &fs_subsys,
+	.kobj   = {.name = "gfs2"},
+	.ktype  = &gfs2_ktype,
+};
+
+/*
+ * display struct lm_lockstruct fields
+ */
+
+struct lockstruct_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct gfs2_sbd *, char *);
+};
+
+#define LOCKSTRUCT_ATTR(name, fmt)                                          \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf)                 \
+{                                                                           \
+	return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_lockstruct.ls_##name); \
+}                                                                           \
+static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name)
+
+LOCKSTRUCT_ATTR(jid,      "%u\n");
+LOCKSTRUCT_ATTR(first,    "%u\n");
+LOCKSTRUCT_ATTR(lvb_size, "%u\n");
+LOCKSTRUCT_ATTR(flags,    "%d\n");
+
+static struct attribute *lockstruct_attrs[] = {
+	&lockstruct_attr_jid.attr,
+	&lockstruct_attr_first.attr,
+	&lockstruct_attr_lvb_size.attr,
+	&lockstruct_attr_flags.attr,
+	NULL,
+};
+
+/*
+ * display struct gfs2_args fields
+ */
+
+struct args_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct gfs2_sbd *, char *);
+};
+
+#define ARGS_ATTR(name, fmt)                                                \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf)                 \
+{                                                                           \
+	return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_args.ar_##name);       \
+}                                                                           \
+static struct args_attr args_attr_##name = __ATTR_RO(name)
+
+ARGS_ATTR(lockproto,       "%s\n");
+ARGS_ATTR(locktable,       "%s\n");
+ARGS_ATTR(hostdata,        "%s\n");
+ARGS_ATTR(spectator,       "%d\n");
+ARGS_ATTR(ignore_local_fs, "%d\n");
+ARGS_ATTR(localcaching,    "%d\n");
+ARGS_ATTR(localflocks,     "%d\n");
+ARGS_ATTR(debug,           "%d\n");
+ARGS_ATTR(upgrade,         "%d\n");
+ARGS_ATTR(num_glockd,      "%u\n");
+ARGS_ATTR(posix_acl,       "%d\n");
+ARGS_ATTR(quota,           "%u\n");
+ARGS_ATTR(suiddir,         "%d\n");
+ARGS_ATTR(data,            "%d\n");
+
+/* one oddball doesn't fit the macro mold */
+static ssize_t noatime_show(struct gfs2_sbd *sdp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			!!test_bit(SDF_NOATIME, &sdp->sd_flags));
+}
+static struct args_attr args_attr_noatime = __ATTR_RO(noatime);
+
+static struct attribute *args_attrs[] = {
+	&args_attr_lockproto.attr,
+	&args_attr_locktable.attr,
+	&args_attr_hostdata.attr,
+	&args_attr_spectator.attr,
+	&args_attr_ignore_local_fs.attr,
+	&args_attr_localcaching.attr,
+	&args_attr_localflocks.attr,
+	&args_attr_debug.attr,
+	&args_attr_upgrade.attr,
+	&args_attr_num_glockd.attr,
+	&args_attr_posix_acl.attr,
+	&args_attr_quota.attr,
+	&args_attr_suiddir.attr,
+	&args_attr_data.attr,
+	&args_attr_noatime.attr,
+	NULL,
+};
+
+/*
+ * display counters from superblock
+ */
+
+struct counters_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct gfs2_sbd *, char *);
+};
+
+#define COUNTERS_ATTR(name, fmt)                                            \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf)                 \
+{                                                                           \
+	return snprintf(buf, PAGE_SIZE, fmt,                                \
+			(unsigned int)atomic_read(&sdp->sd_##name));        \
+}                                                                           \
+static struct counters_attr counters_attr_##name = __ATTR_RO(name)
+
+COUNTERS_ATTR(glock_count,      "%u\n");
+COUNTERS_ATTR(glock_held_count, "%u\n");
+COUNTERS_ATTR(inode_count,      "%u\n");
+COUNTERS_ATTR(reclaimed,        "%u\n");
+
+static struct attribute *counters_attrs[] = {
+	&counters_attr_glock_count.attr,
+	&counters_attr_glock_held_count.attr,
+	&counters_attr_inode_count.attr,
+	&counters_attr_reclaimed.attr,
+	NULL,
+};
+
+/*
+ * get and set struct gfs2_tune fields
+ */
+
+static ssize_t quota_scale_show(struct gfs2_sbd *sdp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%u %u\n",
+			sdp->sd_tune.gt_quota_scale_num,
+			sdp->sd_tune.gt_quota_scale_den);
+}
+
+static ssize_t quota_scale_store(struct gfs2_sbd *sdp, const char *buf,
+				 size_t len)
+{
+	struct gfs2_tune *gt = &sdp->sd_tune;
+	unsigned int x, y;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (sscanf(buf, "%u %u", &x, &y) != 2 || !y)
+		return -EINVAL;
+
+	spin_lock(&gt->gt_spin);
+	gt->gt_quota_scale_num = x;
+	gt->gt_quota_scale_den = y;
+	spin_unlock(&gt->gt_spin);
+	return len;
+}
+
+static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,
+			int check_zero, const char *buf, size_t len)
+{
+	struct gfs2_tune *gt = &sdp->sd_tune;
+	unsigned int x;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	x = simple_strtoul(buf, NULL, 0);
+
+	if (check_zero && !x)
+		return -EINVAL;
+
+	spin_lock(&gt->gt_spin);
+	*field = x;
+	spin_unlock(&gt->gt_spin);
+	return len;
+}
+
+struct tune_attr {
+	struct attribute attr;
+	ssize_t (*show)(struct gfs2_sbd *, char *);
+	ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
+};
+
+#define TUNE_ATTR_3(name, show, store)                                        \
+static struct tune_attr tune_attr_##name = __ATTR(name, 0644, show, store)
+
+#define TUNE_ATTR_2(name, store)                                              \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf)                   \
+{                                                                             \
+	return snprintf(buf, PAGE_SIZE, "%u\n", sdp->sd_tune.gt_##name);      \
+}                                                                             \
+TUNE_ATTR_3(name, name##_show, store)
+
+#define TUNE_ATTR(name, check_zero)                                           \
+static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
+{                                                                             \
+	return tune_set(sdp, &sdp->sd_tune.gt_##name, check_zero, buf, len);  \
+}                                                                             \
+TUNE_ATTR_2(name, name##_store)
+
+#define TUNE_ATTR_DAEMON(name, process)                                       \
+static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
+{                                                                             \
+	ssize_t r = tune_set(sdp, &sdp->sd_tune.gt_##name, 1, buf, len);      \
+	wake_up_process(sdp->sd_##process);                                   \
+	return r;                                                             \
+}                                                                             \
+TUNE_ATTR_2(name, name##_store)
+
+TUNE_ATTR(ilimit, 0);
+TUNE_ATTR(ilimit_tries, 0);
+TUNE_ATTR(ilimit_min, 0);
+TUNE_ATTR(demote_secs, 0);
+TUNE_ATTR(incore_log_blocks, 0);
+TUNE_ATTR(log_flush_secs, 0);
+TUNE_ATTR(jindex_refresh_secs, 0);
+TUNE_ATTR(quota_warn_period, 0);
+TUNE_ATTR(quota_quantum, 0);
+TUNE_ATTR(atime_quantum, 0);
+TUNE_ATTR(max_readahead, 0);
+TUNE_ATTR(complain_secs, 0);
+TUNE_ATTR(reclaim_limit, 0);
+TUNE_ATTR(prefetch_secs, 0);
+TUNE_ATTR(statfs_slow, 0);
+TUNE_ATTR(new_files_jdata, 0);
+TUNE_ATTR(new_files_directio, 0);
+TUNE_ATTR(quota_simul_sync, 1);
+TUNE_ATTR(quota_cache_secs, 1);
+TUNE_ATTR(max_atomic_write, 1);
+TUNE_ATTR(stall_secs, 1);
+TUNE_ATTR(entries_per_readdir, 1);
+TUNE_ATTR(greedy_default, 1);
+TUNE_ATTR(greedy_quantum, 1);
+TUNE_ATTR(greedy_max, 1);
+TUNE_ATTR(statfs_quantum, 1);
+TUNE_ATTR_DAEMON(scand_secs, scand_process);
+TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
+TUNE_ATTR_DAEMON(logd_secs, logd_process);
+TUNE_ATTR_DAEMON(quotad_secs, quotad_process);
+TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store);
+
+static struct attribute *tune_attrs[] = {
+	&tune_attr_ilimit.attr,
+	&tune_attr_ilimit_tries.attr,
+	&tune_attr_ilimit_min.attr,
+	&tune_attr_demote_secs.attr,
+	&tune_attr_incore_log_blocks.attr,
+	&tune_attr_log_flush_secs.attr,
+	&tune_attr_jindex_refresh_secs.attr,
+	&tune_attr_quota_warn_period.attr,
+	&tune_attr_quota_quantum.attr,
+	&tune_attr_atime_quantum.attr,
+	&tune_attr_max_readahead.attr,
+	&tune_attr_complain_secs.attr,
+	&tune_attr_reclaim_limit.attr,
+	&tune_attr_prefetch_secs.attr,
+	&tune_attr_statfs_slow.attr,
+	&tune_attr_quota_simul_sync.attr,
+	&tune_attr_quota_cache_secs.attr,
+	&tune_attr_max_atomic_write.attr,
+	&tune_attr_stall_secs.attr,
+	&tune_attr_entries_per_readdir.attr,
+	&tune_attr_greedy_default.attr,
+	&tune_attr_greedy_quantum.attr,
+	&tune_attr_greedy_max.attr,
+	&tune_attr_statfs_quantum.attr,
+	&tune_attr_scand_secs.attr,
+	&tune_attr_recoverd_secs.attr,
+	&tune_attr_logd_secs.attr,
+	&tune_attr_quotad_secs.attr,
+	&tune_attr_quota_scale.attr,
+	&tune_attr_new_files_jdata.attr,
+	&tune_attr_new_files_directio.attr,
+	NULL,
+};
+
+static struct attribute_group lockstruct_group = {
+	.name = "lockstruct",
+	.attrs = lockstruct_attrs,
+};
+
+static struct attribute_group counters_group = {
+	.name = "counters",
+	.attrs = counters_attrs,
+};
+
+static struct attribute_group args_group = {
+	.name = "args",
+	.attrs = args_attrs,
+};
+
+static struct attribute_group tune_group = {
+	.name = "tune",
+	.attrs = tune_attrs,
+};
+
+int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
+{
+	int error;
+
+	sdp->sd_kobj.kset = &gfs2_kset;
+	sdp->sd_kobj.ktype = &gfs2_ktype;
+
+	error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name);
+	if (error)
+		goto fail;
+
+	error = kobject_register(&sdp->sd_kobj);
+	if (error)
+		goto fail;
+
+	error = sysfs_create_group(&sdp->sd_kobj, &lockstruct_group);
+	if (error)
+		goto fail_reg;
+
+	error = sysfs_create_group(&sdp->sd_kobj, &counters_group);
+	if (error)
+		goto fail_lockstruct;
+
+	error = sysfs_create_group(&sdp->sd_kobj, &args_group);
+	if (error)
+		goto fail_counters;
+
+	error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
+	if (error)
+		goto fail_args;
+
+	return 0;
+
+fail_args:
+	sysfs_remove_group(&sdp->sd_kobj, &args_group);
+fail_counters:
+	sysfs_remove_group(&sdp->sd_kobj, &counters_group);
+fail_lockstruct:
+	sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
+fail_reg:
+	kobject_unregister(&sdp->sd_kobj);
+fail:
+	fs_err(sdp, "error %d adding sysfs files", error);
+	return error;
+}
+
+void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
+{
+	sysfs_remove_group(&sdp->sd_kobj, &tune_group);
+	sysfs_remove_group(&sdp->sd_kobj, &args_group);
+	sysfs_remove_group(&sdp->sd_kobj, &counters_group);
+	sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
+	kobject_unregister(&sdp->sd_kobj);
+}
+
+int gfs2_sys_init(void)
+{
+	gfs2_sys_margs = NULL;
+	spin_lock_init(&gfs2_sys_margs_lock);
+	return kset_register(&gfs2_kset);
+}
+
+void gfs2_sys_uninit(void)
+{
+	kfree(gfs2_sys_margs);
+	kset_unregister(&gfs2_kset);
+}
+
diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h
new file mode 100644
index 0000000..1ca8cda
--- /dev/null
+++ b/fs/gfs2/sys.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __SYS_DOT_H__
+#define __SYS_DOT_H__
+
+#include <linux/spinlock.h>
+struct gfs2_sbd;
+
+/* Allow args to be passed to GFS2 when using an initial ram disk */
+extern char *gfs2_sys_margs;
+extern spinlock_t gfs2_sys_margs_lock;
+
+int gfs2_sys_fs_add(struct gfs2_sbd *sdp);
+void gfs2_sys_fs_del(struct gfs2_sbd *sdp);
+
+int gfs2_sys_init(void);
+void gfs2_sys_uninit(void);
+
+#endif /* __SYS_DOT_H__ */
+
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
new file mode 100644
index 0000000..f8dabf8
--- /dev/null
+++ b/fs/gfs2/trans.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/kallsyms.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "trans.h"
+#include "util.h"
+
+int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
+		     unsigned int revokes)
+{
+	struct gfs2_trans *tr;
+	int error;
+
+	BUG_ON(current->journal_info);
+	BUG_ON(blocks == 0 && revokes == 0);
+
+	tr = kzalloc(sizeof(struct gfs2_trans), GFP_NOFS);
+	if (!tr)
+		return -ENOMEM;
+
+	tr->tr_ip = (unsigned long)__builtin_return_address(0);
+	tr->tr_blocks = blocks;
+	tr->tr_revokes = revokes;
+	tr->tr_reserved = 1;
+	if (blocks)
+		tr->tr_reserved += 6 + blocks;
+	if (revokes)
+		tr->tr_reserved += gfs2_struct2blk(sdp, revokes,
+						   sizeof(u64));
+	INIT_LIST_HEAD(&tr->tr_list_buf);
+
+	gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &tr->tr_t_gh);
+
+	error = gfs2_glock_nq(&tr->tr_t_gh);
+	if (error)
+		goto fail_holder_uninit;
+
+	if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+		tr->tr_t_gh.gh_flags |= GL_NOCACHE;
+		error = -EROFS;
+		goto fail_gunlock;
+	}
+
+	error = gfs2_log_reserve(sdp, tr->tr_reserved);
+	if (error)
+		goto fail_gunlock;
+
+	current->journal_info = tr;
+
+	return 0;
+
+fail_gunlock:
+	gfs2_glock_dq(&tr->tr_t_gh);
+
+fail_holder_uninit:
+	gfs2_holder_uninit(&tr->tr_t_gh);
+	kfree(tr);
+
+	return error;
+}
+
+void gfs2_trans_end(struct gfs2_sbd *sdp)
+{
+	struct gfs2_trans *tr = current->journal_info;
+
+	BUG_ON(!tr);
+	current->journal_info = NULL;
+
+	if (!tr->tr_touched) {
+		gfs2_log_release(sdp, tr->tr_reserved);
+		gfs2_glock_dq(&tr->tr_t_gh);
+		gfs2_holder_uninit(&tr->tr_t_gh);
+		kfree(tr);
+		return;
+	}
+
+	if (gfs2_assert_withdraw(sdp, tr->tr_num_buf <= tr->tr_blocks)) {
+		fs_err(sdp, "tr_num_buf = %u, tr_blocks = %u ",
+		       tr->tr_num_buf, tr->tr_blocks);
+		print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
+	}
+	if (gfs2_assert_withdraw(sdp, tr->tr_num_revoke <= tr->tr_revokes)) {
+		fs_err(sdp, "tr_num_revoke = %u, tr_revokes = %u ",
+		       tr->tr_num_revoke, tr->tr_revokes);
+		print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
+	}
+
+	gfs2_log_commit(sdp, tr);
+        gfs2_glock_dq(&tr->tr_t_gh);
+        gfs2_holder_uninit(&tr->tr_t_gh);
+        kfree(tr);
+
+	if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
+		gfs2_log_flush(sdp, NULL);
+}
+
+void gfs2_trans_add_gl(struct gfs2_glock *gl)
+{
+	lops_add(gl->gl_sbd, &gl->gl_le);
+}
+
+/**
+ * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction
+ * @gl: the glock the buffer belongs to
+ * @bh: The buffer to add
+ * @meta: True in the case of adding metadata
+ *
+ */
+
+void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)
+{
+	struct gfs2_sbd *sdp = gl->gl_sbd;
+	struct gfs2_bufdata *bd;
+
+	bd = bh->b_private;
+	if (bd)
+		gfs2_assert(sdp, bd->bd_gl == gl);
+	else {
+		gfs2_attach_bufdata(gl, bh, meta);
+		bd = bh->b_private;
+	}
+	lops_add(sdp, &bd->bd_le);
+}
+
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno)
+{
+	struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke),
+					 GFP_NOFS | __GFP_NOFAIL);
+	lops_init_le(&rv->rv_le, &gfs2_revoke_lops);
+	rv->rv_blkno = blkno;
+	lops_add(sdp, &rv->rv_le);
+}
+
+void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
+{
+	struct gfs2_revoke *rv;
+	int found = 0;
+
+	gfs2_log_lock(sdp);
+
+	list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) {
+		if (rv->rv_blkno == blkno) {
+			list_del(&rv->rv_le.le_list);
+			gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
+			sdp->sd_log_num_revoke--;
+			found = 1;
+			break;
+		}
+	}
+
+	gfs2_log_unlock(sdp);
+
+	if (found) {
+		struct gfs2_trans *tr = current->journal_info;
+		kfree(rv);
+		tr->tr_num_revoke_rm++;
+	}
+}
+
+void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd)
+{
+	lops_add(rgd->rd_sbd, &rgd->rd_le);
+}
+
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
new file mode 100644
index 0000000..23d4cbe
--- /dev/null
+++ b/fs/gfs2/trans.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __TRANS_DOT_H__
+#define __TRANS_DOT_H__
+
+#include <linux/buffer_head.h>
+struct gfs2_sbd;
+struct gfs2_rgrpd;
+struct gfs2_glock;
+
+#define RES_DINODE	1
+#define RES_INDIRECT	1
+#define RES_JDATA	1
+#define RES_DATA	1
+#define RES_LEAF	1
+#define RES_RG_BIT	2
+#define RES_EATTR	1
+#define RES_STATFS	1
+#define RES_QUOTA	2
+
+int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
+		     unsigned int revokes);
+
+void gfs2_trans_end(struct gfs2_sbd *sdp);
+
+void gfs2_trans_add_gl(struct gfs2_glock *gl);
+void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno);
+void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
+void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
+
+#endif /* __TRANS_DOT_H__ */
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
new file mode 100644
index 0000000..196c604
--- /dev/null
+++ b/fs/gfs2/util.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/crc32.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "lm.h"
+#include "util.h"
+
+kmem_cache_t *gfs2_glock_cachep __read_mostly;
+kmem_cache_t *gfs2_inode_cachep __read_mostly;
+kmem_cache_t *gfs2_bufdata_cachep __read_mostly;
+
+void gfs2_assert_i(struct gfs2_sbd *sdp)
+{
+	printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n",
+	       sdp->sd_fsname);
+}
+
+/**
+ * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false
+ * Returns: -1 if this call withdrew the machine,
+ *          -2 if it was already withdrawn
+ */
+
+int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
+			   const char *function, char *file, unsigned int line)
+{
+	int me;
+	me = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: assertion \"%s\" failed\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname, assertion,
+		sdp->sd_fsname, function, file, line);
+	dump_stack();
+	return (me) ? -1 : -2;
+}
+
+/**
+ * gfs2_assert_warn_i - Print a message to the console if @assertion is false
+ * Returns: -1 if we printed something
+ *          -2 if we didn't
+ */
+
+int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
+		       const char *function, char *file, unsigned int line)
+{
+	if (time_before(jiffies,
+			sdp->sd_last_warning +
+			gfs2_tune_get(sdp, gt_complain_secs) * HZ))
+		return -2;
+
+	printk(KERN_WARNING
+	       "GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
+	       "GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+	       sdp->sd_fsname, assertion,
+	       sdp->sd_fsname, function, file, line);
+
+	if (sdp->sd_args.ar_debug)
+		BUG();
+	else
+		dump_stack();
+
+	sdp->sd_last_warning = jiffies;
+
+	return -1;
+}
+
+/**
+ * gfs2_consist_i - Flag a filesystem consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ *          0 if it was already withdrawn
+ */
+
+int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide, const char *function,
+		   char *file, unsigned int line)
+{
+	int rv;
+	rv = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: filesystem consistency error\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname,
+		sdp->sd_fsname, function, file, line);
+	return rv;
+}
+
+/**
+ * gfs2_consist_inode_i - Flag an inode consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ *          0 if it was already withdrawn
+ */
+
+int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide,
+			 const char *function, char *file, unsigned int line)
+{
+	struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+	int rv;
+	rv = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: filesystem consistency error\n"
+		"GFS2: fsid=%s:   inode = %llu %llu\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname,
+		sdp->sd_fsname, (unsigned long long)ip->i_num.no_formal_ino,
+		(unsigned long long)ip->i_num.no_addr,
+		sdp->sd_fsname, function, file, line);
+	return rv;
+}
+
+/**
+ * gfs2_consist_rgrpd_i - Flag a RG consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ *          0 if it was already withdrawn
+ */
+
+int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide,
+			 const char *function, char *file, unsigned int line)
+{
+	struct gfs2_sbd *sdp = rgd->rd_sbd;
+	int rv;
+	rv = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: filesystem consistency error\n"
+		"GFS2: fsid=%s:   RG = %llu\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname,
+		sdp->sd_fsname, (unsigned long long)rgd->rd_ri.ri_addr,
+		sdp->sd_fsname, function, file, line);
+	return rv;
+}
+
+/**
+ * gfs2_meta_check_ii - Flag a magic number consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ *          -2 if it was already withdrawn
+ */
+
+int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+		       const char *type, const char *function, char *file,
+		       unsigned int line)
+{
+	int me;
+	me = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: invalid metadata block\n"
+		"GFS2: fsid=%s:   bh = %llu (%s)\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname,
+		sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type,
+		sdp->sd_fsname, function, file, line);
+	return (me) ? -1 : -2;
+}
+
+/**
+ * gfs2_metatype_check_ii - Flag a metadata type consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ *          -2 if it was already withdrawn
+ */
+
+int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+			   u16 type, u16 t, const char *function,
+			   char *file, unsigned int line)
+{
+	int me;
+	me = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: invalid metadata block\n"
+		"GFS2: fsid=%s:   bh = %llu (type: exp=%u, found=%u)\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname,
+		sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type, t,
+		sdp->sd_fsname, function, file, line);
+	return (me) ? -1 : -2;
+}
+
+/**
+ * gfs2_io_error_i - Flag an I/O error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ *          0 if it was already withdrawn
+ */
+
+int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file,
+		    unsigned int line)
+{
+	int rv;
+	rv = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: I/O error\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname,
+		sdp->sd_fsname, function, file, line);
+	return rv;
+}
+
+/**
+ * gfs2_io_error_bh_i - Flag a buffer I/O error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ *          0 if it was already withdrawn
+ */
+
+int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
+		       const char *function, char *file, unsigned int line)
+{
+	int rv;
+	rv = gfs2_lm_withdraw(sdp,
+		"GFS2: fsid=%s: fatal: I/O error\n"
+		"GFS2: fsid=%s:   block = %llu\n"
+		"GFS2: fsid=%s:   function = %s, file = %s, line = %u\n",
+		sdp->sd_fsname,
+		sdp->sd_fsname, (unsigned long long)bh->b_blocknr,
+		sdp->sd_fsname, function, file, line);
+	return rv;
+}
+
+void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
+		      unsigned int bit, int new_value)
+{
+	unsigned int c, o, b = bit;
+	int old_value;
+
+	c = b / (8 * PAGE_SIZE);
+	b %= 8 * PAGE_SIZE;
+	o = b / 8;
+	b %= 8;
+
+	old_value = (bitmap[c][o] & (1 << b));
+	gfs2_assert_withdraw(sdp, !old_value != !new_value);
+
+	if (new_value)
+		bitmap[c][o] |= 1 << b;
+	else
+		bitmap[c][o] &= ~(1 << b);
+}
+
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
new file mode 100644
index 0000000..76a5089
--- /dev/null
+++ b/fs/gfs2/util.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __UTIL_DOT_H__
+#define __UTIL_DOT_H__
+
+#include "incore.h"
+
+#define fs_printk(level, fs, fmt, arg...) \
+	printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg)
+
+#define fs_info(fs, fmt, arg...) \
+	fs_printk(KERN_INFO , fs , fmt , ## arg)
+
+#define fs_warn(fs, fmt, arg...) \
+	fs_printk(KERN_WARNING , fs , fmt , ## arg)
+
+#define fs_err(fs, fmt, arg...) \
+	fs_printk(KERN_ERR, fs , fmt , ## arg)
+
+
+void gfs2_assert_i(struct gfs2_sbd *sdp);
+
+#define gfs2_assert(sdp, assertion) \
+do { \
+	if (unlikely(!(assertion))) { \
+		gfs2_assert_i(sdp); \
+		BUG(); \
+        } \
+} while (0)
+
+
+int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
+			   const char *function, char *file, unsigned int line);
+
+#define gfs2_assert_withdraw(sdp, assertion) \
+((likely(assertion)) ? 0 : gfs2_assert_withdraw_i((sdp), #assertion, \
+					__FUNCTION__, __FILE__, __LINE__))
+
+
+int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
+		       const char *function, char *file, unsigned int line);
+
+#define gfs2_assert_warn(sdp, assertion) \
+((likely(assertion)) ? 0 : gfs2_assert_warn_i((sdp), #assertion, \
+					__FUNCTION__, __FILE__, __LINE__))
+
+
+int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide,
+		   const char *function, char *file, unsigned int line);
+
+#define gfs2_consist(sdp) \
+gfs2_consist_i((sdp), 0, __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide,
+			 const char *function, char *file, unsigned int line);
+
+#define gfs2_consist_inode(ip) \
+gfs2_consist_inode_i((ip), 0, __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide,
+			 const char *function, char *file, unsigned int line);
+
+#define gfs2_consist_rgrpd(rgd) \
+gfs2_consist_rgrpd_i((rgd), 0, __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+		       const char *type, const char *function,
+		       char *file, unsigned int line);
+
+static inline int gfs2_meta_check_i(struct gfs2_sbd *sdp,
+				    struct buffer_head *bh,
+				    const char *function,
+				    char *file, unsigned int line)
+{
+	struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
+	u32 magic = mh->mh_magic;
+	magic = be32_to_cpu(magic);
+	if (unlikely(magic != GFS2_MAGIC))
+		return gfs2_meta_check_ii(sdp, bh, "magic number", function,
+					  file, line);
+	return 0;
+}
+
+#define gfs2_meta_check(sdp, bh) \
+gfs2_meta_check_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+			   u16 type, u16 t,
+			   const char *function,
+			   char *file, unsigned int line);
+
+static inline int gfs2_metatype_check_i(struct gfs2_sbd *sdp,
+					struct buffer_head *bh,
+					u16 type,
+					const char *function,
+					char *file, unsigned int line)
+{
+	struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
+	u32 magic = mh->mh_magic;
+	u16 t = be32_to_cpu(mh->mh_type);
+	magic = be32_to_cpu(magic);
+	if (unlikely(magic != GFS2_MAGIC))
+		return gfs2_meta_check_ii(sdp, bh, "magic number", function,
+					  file, line);
+        if (unlikely(t != type))
+		return gfs2_metatype_check_ii(sdp, bh, type, t, function,
+					      file, line);
+	return 0;
+}
+
+#define gfs2_metatype_check(sdp, bh, type) \
+gfs2_metatype_check_i((sdp), (bh), (type), __FUNCTION__, __FILE__, __LINE__)
+
+static inline void gfs2_metatype_set(struct buffer_head *bh, u16 type,
+				     u16 format)
+{
+	struct gfs2_meta_header *mh;
+	mh = (struct gfs2_meta_header *)bh->b_data;
+	mh->mh_type = cpu_to_be32(type);
+	mh->mh_format = cpu_to_be32(format);
+}
+
+
+int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function,
+		    char *file, unsigned int line);
+
+#define gfs2_io_error(sdp) \
+gfs2_io_error_i((sdp), __FUNCTION__, __FILE__, __LINE__);
+
+
+int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
+		       const char *function, char *file, unsigned int line);
+
+#define gfs2_io_error_bh(sdp, bh) \
+gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__);
+
+
+extern kmem_cache_t *gfs2_glock_cachep;
+extern kmem_cache_t *gfs2_inode_cachep;
+extern kmem_cache_t *gfs2_bufdata_cachep;
+
+static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
+					   unsigned int *p)
+{
+	unsigned int x;
+	spin_lock(&gt->gt_spin);
+	x = *p;
+	spin_unlock(&gt->gt_spin);
+	return x;
+}
+
+#define gfs2_tune_get(sdp, field) \
+gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
+
+void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
+		      unsigned int bit, int new_value);
+
+#endif /* __UTIL_DOT_H__ */
+
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index e7ba0c3..c04b3a1 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -6,7 +6,6 @@
  *  (C) 1991  Linus Torvalds - minix filesystem
  */
 
-#include <linux/config.h>	/* Joliet? */
 #include <linux/smp_lock.h>
 #include "isofs.h"
 
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 87e1d03..e8c7765 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -144,42 +144,12 @@
  */
 
 /*
- * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
- * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
- */
-static void nlmclnt_prepare_reclaim(struct nlm_host *host)
-{
-	down_write(&host->h_rwsem);
-	host->h_monitored = 0;
-	host->h_state++;
-	host->h_nextrebind = 0;
-	nlm_rebind_host(host);
-
-	/*
-	 * Mark the locks for reclaiming.
-	 */
-	list_splice_init(&host->h_granted, &host->h_reclaim);
-
-	dprintk("NLM: reclaiming locks for host %s\n", host->h_name);
-}
-
-static void nlmclnt_finish_reclaim(struct nlm_host *host)
-{
-	host->h_reclaiming = 0;
-	up_write(&host->h_rwsem);
-	dprintk("NLM: done reclaiming locks for host %s", host->h_name);
-}
-
-/*
  * Reclaim all locks on server host. We do this by spawning a separate
  * reclaimer thread.
  */
 void
-nlmclnt_recovery(struct nlm_host *host, u32 newstate)
+nlmclnt_recovery(struct nlm_host *host)
 {
-	if (host->h_nsmstate == newstate)
-		return;
-	host->h_nsmstate = newstate;
 	if (!host->h_reclaiming++) {
 		nlm_get_host(host);
 		__module_get(THIS_MODULE);
@@ -199,18 +169,30 @@
 	daemonize("%s-reclaim", host->h_name);
 	allow_signal(SIGKILL);
 
+	down_write(&host->h_rwsem);
+
 	/* This one ensures that our parent doesn't terminate while the
 	 * reclaim is in progress */
 	lock_kernel();
 	lockd_up(0); /* note: this cannot fail as lockd is already running */
 
-	nlmclnt_prepare_reclaim(host);
-	/* First, reclaim all locks that have been marked. */
+	dprintk("lockd: reclaiming locks for host %s", host->h_name);
+
 restart:
 	nsmstate = host->h_nsmstate;
+
+	/* Force a portmap getport - the peer's lockd will
+	 * most likely end up on a different port.
+	 */
+	host->h_nextrebind = jiffies;
+	nlm_rebind_host(host);
+
+	/* First, reclaim all locks that have been granted. */
+	list_splice_init(&host->h_granted, &host->h_reclaim);
 	list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
 		list_del_init(&fl->fl_u.nfs_fl.list);
 
+		/* Why are we leaking memory here? --okir */
 		if (signalled())
 			continue;
 		if (nlmclnt_reclaim(host, fl) != 0)
@@ -218,11 +200,13 @@
 		list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
 		if (host->h_nsmstate != nsmstate) {
 			/* Argh! The server rebooted again! */
-			list_splice_init(&host->h_granted, &host->h_reclaim);
 			goto restart;
 		}
 	}
-	nlmclnt_finish_reclaim(host);
+
+	host->h_reclaiming = 0;
+	up_write(&host->h_rwsem);
+	dprintk("NLM: done reclaiming locks for host %s", host->h_name);
 
 	/* Now, wake up all processes that sleep on a blocked lock */
 	list_for_each_entry(block, &nlm_blocked, b_list) {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 0116729..3d84f60 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -36,14 +36,14 @@
 /*
  * Cookie counter for NLM requests
  */
-static u32	nlm_cookie = 0x1234;
+static atomic_t	nlm_cookie = ATOMIC_INIT(0x1234);
 
-static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
+void nlmclnt_next_cookie(struct nlm_cookie *c)
 {
-	memcpy(c->data, &nlm_cookie, 4);
-	memset(c->data+4, 0, 4);
+	u32	cookie = atomic_inc_return(&nlm_cookie);
+
+	memcpy(c->data, &cookie, 4);
 	c->len=4;
-	nlm_cookie++;
 }
 
 static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
@@ -153,6 +153,7 @@
 {
 	struct rpc_clnt		*client = NFS_CLIENT(inode);
 	struct sockaddr_in	addr;
+	struct nfs_server	*nfssrv = NFS_SERVER(inode);
 	struct nlm_host		*host;
 	struct nlm_rqst		*call;
 	sigset_t		oldset;
@@ -166,7 +167,9 @@
 	}
 
 	rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr));
-	host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers);
+	host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers,
+				   nfssrv->nfs_client->cl_hostname,
+				   strlen(nfssrv->nfs_client->cl_hostname));
 	if (host == NULL)
 		return -ENOLCK;
 
@@ -499,7 +502,7 @@
 	unsigned char fl_flags = fl->fl_flags;
 	int status = -ENOLCK;
 
-	if (!host->h_monitored && nsm_monitor(host) < 0) {
+	if (nsm_monitor(host) < 0) {
 		printk(KERN_NOTICE "lockd: failed to monitor %s\n",
 					host->h_name);
 		goto out;
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index a0d0b58..fb24a97 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -27,46 +27,60 @@
 #define NLM_HOST_EXPIRE		((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
 #define NLM_HOST_COLLECT	((nrhosts > NLM_HOST_MAX)? 120 * HZ :  60 * HZ)
 
-static struct nlm_host *	nlm_hosts[NLM_HOST_NRHASH];
+static struct hlist_head	nlm_hosts[NLM_HOST_NRHASH];
 static unsigned long		next_gc;
 static int			nrhosts;
 static DEFINE_MUTEX(nlm_host_mutex);
 
 
 static void			nlm_gc_hosts(void);
+static struct nsm_handle *	__nsm_find(const struct sockaddr_in *,
+					const char *, int, int);
 
 /*
  * Find an NLM server handle in the cache. If there is none, create it.
  */
 struct nlm_host *
-nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
+nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
+			const char *hostname, int hostname_len)
 {
-	return nlm_lookup_host(0, sin, proto, version);
+	return nlm_lookup_host(0, sin, proto, version,
+			       hostname, hostname_len);
 }
 
 /*
  * Find an NLM client handle in the cache. If there is none, create it.
  */
 struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp)
+nlmsvc_lookup_host(struct svc_rqst *rqstp,
+			const char *hostname, int hostname_len)
 {
 	return nlm_lookup_host(1, &rqstp->rq_addr,
-			       rqstp->rq_prot, rqstp->rq_vers);
+			       rqstp->rq_prot, rqstp->rq_vers,
+			       hostname, hostname_len);
 }
 
 /*
  * Common host lookup routine for server & client
  */
 struct nlm_host *
-nlm_lookup_host(int server, struct sockaddr_in *sin,
-					int proto, int version)
+nlm_lookup_host(int server, const struct sockaddr_in *sin,
+					int proto, int version,
+					const char *hostname,
+					int hostname_len)
 {
-	struct nlm_host	*host, **hp;
-	u32		addr;
+	struct hlist_head *chain;
+	struct hlist_node *pos;
+	struct nlm_host	*host;
+	struct nsm_handle *nsm = NULL;
 	int		hash;
 
-	dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
-			(unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
+	dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n",
+			NIPQUAD(sin->sin_addr.s_addr), proto, version,
+			server? "server" : "client",
+			hostname_len,
+			hostname? hostname : "<none>");
+
 
 	hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
 
@@ -76,7 +90,22 @@
 	if (time_after_eq(jiffies, next_gc))
 		nlm_gc_hosts();
 
-	for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
+	/* We may keep several nlm_host objects for a peer, because each
+	 * nlm_host is identified by
+	 * (address, protocol, version, server/client)
+	 * We could probably simplify this a little by putting all those
+	 * different NLM rpc_clients into one single nlm_host object.
+	 * This would allow us to have one nlm_host per address.
+	 */
+	chain = &nlm_hosts[hash];
+	hlist_for_each_entry(host, pos, chain, h_hash) {
+		if (!nlm_cmp_addr(&host->h_addr, sin))
+			continue;
+
+		/* See if we have an NSM handle for this client */
+		if (!nsm)
+			nsm = host->h_nsmhandle;
+
 		if (host->h_proto != proto)
 			continue;
 		if (host->h_version != version)
@@ -84,28 +113,30 @@
 		if (host->h_server != server)
 			continue;
 
-		if (nlm_cmp_addr(&host->h_addr, sin)) {
-			if (hp != nlm_hosts + hash) {
-				*hp = host->h_next;
-				host->h_next = nlm_hosts[hash];
-				nlm_hosts[hash] = host;
-			}
-			nlm_get_host(host);
-			mutex_unlock(&nlm_host_mutex);
-			return host;
-		}
-	}
+		/* Move to head of hash chain. */
+		hlist_del(&host->h_hash);
+		hlist_add_head(&host->h_hash, chain);
 
-	/* Ooops, no host found, create it */
-	dprintk("lockd: creating host entry\n");
+		nlm_get_host(host);
+		goto out;
+	}
+	if (nsm)
+		atomic_inc(&nsm->sm_count);
+
+	host = NULL;
+
+	/* Sadly, the host isn't in our hash table yet. See if
+	 * we have an NSM handle for it. If not, create one.
+	 */
+	if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len)))
+		goto out;
 
 	host = kzalloc(sizeof(*host), GFP_KERNEL);
-	if (!host)
-		goto nohost;
-
-	addr = sin->sin_addr.s_addr;
-	sprintf(host->h_name, "%u.%u.%u.%u", NIPQUAD(addr));
-
+	if (!host) {
+		nsm_release(nsm);
+		goto out;
+	}
+	host->h_name	   = nsm->sm_name;
 	host->h_addr       = *sin;
 	host->h_addr.sin_port = 0;	/* ouch! */
 	host->h_version    = version;
@@ -119,9 +150,9 @@
 	init_rwsem(&host->h_rwsem);
 	host->h_state      = 0;			/* pseudo NSM state */
 	host->h_nsmstate   = 0;			/* real NSM state */
+	host->h_nsmhandle  = nsm;
 	host->h_server	   = server;
-	host->h_next       = nlm_hosts[hash];
-	nlm_hosts[hash]    = host;
+	hlist_add_head(&host->h_hash, chain);
 	INIT_LIST_HEAD(&host->h_lockowners);
 	spin_lock_init(&host->h_lock);
 	INIT_LIST_HEAD(&host->h_granted);
@@ -130,35 +161,39 @@
 	if (++nrhosts > NLM_HOST_MAX)
 		next_gc = 0;
 
-nohost:
+out:
 	mutex_unlock(&nlm_host_mutex);
 	return host;
 }
 
-struct nlm_host *
-nlm_find_client(void)
+/*
+ * Destroy a host
+ */
+static void
+nlm_destroy_host(struct nlm_host *host)
 {
-	/* find a nlm_host for a client for which h_killed == 0.
-	 * and return it
+	struct rpc_clnt	*clnt;
+
+	BUG_ON(!list_empty(&host->h_lockowners));
+	BUG_ON(atomic_read(&host->h_count));
+
+	/*
+	 * Release NSM handle and unmonitor host.
 	 */
-	int hash;
-	mutex_lock(&nlm_host_mutex);
-	for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
-		struct nlm_host *host, **hp;
-		for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
-			if (host->h_server &&
-			    host->h_killed == 0) {
-				nlm_get_host(host);
-				mutex_unlock(&nlm_host_mutex);
-				return host;
-			}
+	nsm_unmonitor(host);
+
+	if ((clnt = host->h_rpcclnt) != NULL) {
+		if (atomic_read(&clnt->cl_users)) {
+			printk(KERN_WARNING
+				"lockd: active RPC handle\n");
+			clnt->cl_dead = 1;
+		} else {
+			rpc_destroy_client(host->h_rpcclnt);
 		}
 	}
-	mutex_unlock(&nlm_host_mutex);
-	return NULL;
+	kfree(host);
 }
 
-				
 /*
  * Create the NLM RPC client for an NLM peer
  */
@@ -260,22 +295,82 @@
 }
 
 /*
+ * We were notified that the host indicated by address &sin
+ * has rebooted.
+ * Release all resources held by that peer.
+ */
+void nlm_host_rebooted(const struct sockaddr_in *sin,
+				const char *hostname, int hostname_len,
+				u32 new_state)
+{
+	struct hlist_head *chain;
+	struct hlist_node *pos;
+	struct nsm_handle *nsm;
+	struct nlm_host	*host;
+
+	dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
+			hostname, NIPQUAD(sin->sin_addr));
+
+	/* Find the NSM handle for this peer */
+	if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
+		return;
+
+	/* When reclaiming locks on this peer, make sure that
+	 * we set up a new notification */
+	nsm->sm_monitored = 0;
+
+	/* Mark all hosts tied to this NSM state as having rebooted.
+	 * We run the loop repeatedly, because we drop the host table
+	 * lock for this.
+	 * To avoid processing a host several times, we match the nsmstate.
+	 */
+again:	mutex_lock(&nlm_host_mutex);
+	for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+		hlist_for_each_entry(host, pos, chain, h_hash) {
+			if (host->h_nsmhandle == nsm
+			 && host->h_nsmstate != new_state) {
+				host->h_nsmstate = new_state;
+				host->h_state++;
+
+				nlm_get_host(host);
+				mutex_unlock(&nlm_host_mutex);
+
+				if (host->h_server) {
+					/* We're server for this guy, just ditch
+					 * all the locks he held. */
+					nlmsvc_free_host_resources(host);
+				} else {
+					/* He's the server, initiate lock recovery. */
+					nlmclnt_recovery(host);
+				}
+
+				nlm_release_host(host);
+				goto again;
+			}
+		}
+	}
+
+	mutex_unlock(&nlm_host_mutex);
+}
+
+/*
  * Shut down the hosts module.
  * Note that this routine is called only at server shutdown time.
  */
 void
 nlm_shutdown_hosts(void)
 {
+	struct hlist_head *chain;
+	struct hlist_node *pos;
 	struct nlm_host	*host;
-	int		i;
 
 	dprintk("lockd: shutting down host module\n");
 	mutex_lock(&nlm_host_mutex);
 
 	/* First, make all hosts eligible for gc */
 	dprintk("lockd: nuking all hosts...\n");
-	for (i = 0; i < NLM_HOST_NRHASH; i++) {
-		for (host = nlm_hosts[i]; host; host = host->h_next)
+	for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+		hlist_for_each_entry(host, pos, chain, h_hash)
 			host->h_expires = jiffies - 1;
 	}
 
@@ -287,8 +382,8 @@
 	if (nrhosts) {
 		printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
 		dprintk("lockd: %d hosts left:\n", nrhosts);
-		for (i = 0; i < NLM_HOST_NRHASH; i++) {
-			for (host = nlm_hosts[i]; host; host = host->h_next) {
+		for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+			hlist_for_each_entry(host, pos, chain, h_hash) {
 				dprintk("       %s (cnt %d use %d exp %ld)\n",
 					host->h_name, atomic_read(&host->h_count),
 					host->h_inuse, host->h_expires);
@@ -305,45 +400,32 @@
 static void
 nlm_gc_hosts(void)
 {
-	struct nlm_host	**q, *host;
-	struct rpc_clnt	*clnt;
-	int		i;
+	struct hlist_head *chain;
+	struct hlist_node *pos, *next;
+	struct nlm_host	*host;
 
 	dprintk("lockd: host garbage collection\n");
-	for (i = 0; i < NLM_HOST_NRHASH; i++) {
-		for (host = nlm_hosts[i]; host; host = host->h_next)
+	for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+		hlist_for_each_entry(host, pos, chain, h_hash)
 			host->h_inuse = 0;
 	}
 
 	/* Mark all hosts that hold locks, blocks or shares */
 	nlmsvc_mark_resources();
 
-	for (i = 0; i < NLM_HOST_NRHASH; i++) {
-		q = &nlm_hosts[i];
-		while ((host = *q) != NULL) {
+	for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+		hlist_for_each_entry_safe(host, pos, next, chain, h_hash) {
 			if (atomic_read(&host->h_count) || host->h_inuse
 			 || time_before(jiffies, host->h_expires)) {
 				dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n",
 					host->h_name, atomic_read(&host->h_count),
 					host->h_inuse, host->h_expires);
-				q = &host->h_next;
 				continue;
 			}
 			dprintk("lockd: delete host %s\n", host->h_name);
-			*q = host->h_next;
-			/* Don't unmonitor hosts that have been invalidated */
-			if (host->h_monitored && !host->h_killed)
-				nsm_unmonitor(host);
-			if ((clnt = host->h_rpcclnt) != NULL) {
-				if (atomic_read(&clnt->cl_users)) {
-					printk(KERN_WARNING
-						"lockd: active RPC handle\n");
-					clnt->cl_dead = 1;
-				} else {
-					rpc_destroy_client(host->h_rpcclnt);
-				}
-			}
-			kfree(host);
+			hlist_del_init(&host->h_hash);
+
+			nlm_destroy_host(host);
 			nrhosts--;
 		}
 	}
@@ -351,3 +433,88 @@
 	next_gc = jiffies + NLM_HOST_COLLECT;
 }
 
+
+/*
+ * Manage NSM handles
+ */
+static LIST_HEAD(nsm_handles);
+static DEFINE_MUTEX(nsm_mutex);
+
+static struct nsm_handle *
+__nsm_find(const struct sockaddr_in *sin,
+		const char *hostname, int hostname_len,
+		int create)
+{
+	struct nsm_handle *nsm = NULL;
+	struct list_head *pos;
+
+	if (!sin)
+		return NULL;
+
+	if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
+		if (printk_ratelimit()) {
+			printk(KERN_WARNING "Invalid hostname \"%.*s\" "
+					    "in NFS lock request\n",
+				hostname_len, hostname);
+		}
+		return NULL;
+	}
+
+	mutex_lock(&nsm_mutex);
+	list_for_each(pos, &nsm_handles) {
+		nsm = list_entry(pos, struct nsm_handle, sm_link);
+
+		if (hostname && nsm_use_hostnames) {
+			if (strlen(nsm->sm_name) != hostname_len
+			 || memcmp(nsm->sm_name, hostname, hostname_len))
+				continue;
+		} else if (!nlm_cmp_addr(&nsm->sm_addr, sin))
+			continue;
+		atomic_inc(&nsm->sm_count);
+		goto out;
+	}
+
+	if (!create) {
+		nsm = NULL;
+		goto out;
+	}
+
+	nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
+	if (nsm != NULL) {
+		nsm->sm_addr = *sin;
+		nsm->sm_name = (char *) (nsm + 1);
+		memcpy(nsm->sm_name, hostname, hostname_len);
+		nsm->sm_name[hostname_len] = '\0';
+		atomic_set(&nsm->sm_count, 1);
+
+		list_add(&nsm->sm_link, &nsm_handles);
+	}
+
+out:
+	mutex_unlock(&nsm_mutex);
+	return nsm;
+}
+
+struct nsm_handle *
+nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len)
+{
+	return __nsm_find(sin, hostname, hostname_len, 1);
+}
+
+/*
+ * Release an NSM handle
+ */
+void
+nsm_release(struct nsm_handle *nsm)
+{
+	if (!nsm)
+		return;
+	if (atomic_dec_and_test(&nsm->sm_count)) {
+		mutex_lock(&nsm_mutex);
+		if (atomic_read(&nsm->sm_count) == 0) {
+			list_del(&nsm->sm_link);
+			kfree(nsm);
+		}
+		mutex_unlock(&nsm_mutex);
+	}
+}
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index a816b92..e0179f8 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -24,13 +24,13 @@
 /*
  * Local NSM state
  */
-u32				nsm_local_state;
+int				nsm_local_state;
 
 /*
  * Common procedure for SM_MON/SM_UNMON calls
  */
 static int
-nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
+nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
 {
 	struct rpc_clnt	*clnt;
 	int		status;
@@ -46,10 +46,11 @@
 		goto out;
 	}
 
-	args.addr = host->h_addr.sin_addr.s_addr;
-	args.proto= (host->h_proto<<1) | host->h_server;
+	memset(&args, 0, sizeof(args));
+	args.mon_name = nsm->sm_name;
+	args.addr = nsm->sm_addr.sin_addr.s_addr;
 	args.prog = NLM_PROGRAM;
-	args.vers = host->h_version;
+	args.vers = 3;
 	args.proc = NLMPROC_NSM_NOTIFY;
 	memset(res, 0, sizeof(*res));
 
@@ -70,17 +71,22 @@
 int
 nsm_monitor(struct nlm_host *host)
 {
+	struct nsm_handle *nsm = host->h_nsmhandle;
 	struct nsm_res	res;
 	int		status;
 
 	dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
+	BUG_ON(nsm == NULL);
 
-	status = nsm_mon_unmon(host, SM_MON, &res);
+	if (nsm->sm_monitored)
+		return 0;
+
+	status = nsm_mon_unmon(nsm, SM_MON, &res);
 
 	if (status < 0 || res.status != 0)
 		printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
 	else
-		host->h_monitored = 1;
+		nsm->sm_monitored = 1;
 	return status;
 }
 
@@ -90,16 +96,26 @@
 int
 nsm_unmonitor(struct nlm_host *host)
 {
+	struct nsm_handle *nsm = host->h_nsmhandle;
 	struct nsm_res	res;
-	int		status;
+	int		status = 0;
 
-	dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+	if (nsm == NULL)
+		return 0;
+	host->h_nsmhandle = NULL;
 
-	status = nsm_mon_unmon(host, SM_UNMON, &res);
-	if (status < 0)
-		printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
-	else
-		host->h_monitored = 0;
+	if (atomic_read(&nsm->sm_count) == 1
+	 && nsm->sm_monitored && !nsm->sm_sticky) {
+		dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+
+		status = nsm_mon_unmon(nsm, SM_UNMON, &res);
+		if (status < 0)
+			printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
+					host->h_name);
+		else
+			nsm->sm_monitored = 0;
+	}
+	nsm_release(nsm);
 	return status;
 }
 
@@ -135,7 +151,7 @@
 static u32 *
 xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
 {
-	char	buffer[20];
+	char	buffer[20], *name;
 
 	/*
 	 * Use the dotted-quad IP address of the remote host as
@@ -143,8 +159,13 @@
 	 * hostname first for whatever remote hostname it receives,
 	 * so this works alright.
 	 */
-	sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
-	if (!(p = xdr_encode_string(p, buffer))
+	if (nsm_use_hostnames) {
+		name = argp->mon_name;
+	} else {
+		sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
+		name = buffer;
+	}
+	if (!(p = xdr_encode_string(p, name))
 	 || !(p = xdr_encode_string(p, utsname()->nodename)))
 		return ERR_PTR(-EIO);
 	*p++ = htonl(argp->prog);
@@ -160,9 +181,11 @@
 	p = xdr_encode_common(rqstp, p, argp);
 	if (IS_ERR(p))
 		return PTR_ERR(p);
+
+	/* Surprise - there may even be room for an IPv6 address now */
 	*p++ = argp->addr;
-	*p++ = argp->vers;
-	*p++ = argp->proto;
+	*p++ = 0;
+	*p++ = 0;
 	*p++ = 0;
 	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
 	return 0;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 3cc369e..6341392 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -33,6 +33,7 @@
 #include <linux/sunrpc/svcsock.h>
 #include <net/ip.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
 #include <linux/nfs.h>
 
 #define NLMDBG_FACILITY		NLMDBG_SVC
@@ -61,6 +62,7 @@
 static unsigned long		nlm_grace_period;
 static unsigned long		nlm_timeout = LOCKD_DFLT_TIMEO;
 static int			nlm_udpport, nlm_tcpport;
+int				nsm_use_hostnames = 0;
 
 /*
  * Constants needed for the sysctl interface.
@@ -395,6 +397,22 @@
 		.extra1		= (int *) &nlm_port_min,
 		.extra2		= (int *) &nlm_port_max,
 	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "nsm_use_hostnames",
+		.data		= &nsm_use_hostnames,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
+	{
+		.ctl_name	= CTL_UNNUMBERED,
+		.procname	= "nsm_local_state",
+		.data		= &nsm_local_state,
+		.maxlen		= sizeof(int),
+		.mode		= 0644,
+		.proc_handler	= &proc_dointvec,
+	},
 	{ .ctl_name = 0 }
 };
 
@@ -483,6 +501,7 @@
 		  &nlm_udpport, 0644);
 module_param_call(nlm_tcpport, param_set_port, param_get_int,
 		  &nlm_tcpport, 0644);
+module_param(nsm_use_hostnames, bool, 0644);
 
 /*
  * Initialising and terminating the module.
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index a2dd9cc..fa370f6 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -38,8 +38,8 @@
 		return nlm_lck_denied_nolocks;
 
 	/* Obtain host handle */
-	if (!(host = nlmsvc_lookup_host(rqstp))
-	 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+	if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
+	 || (argp->monitor && nsm_monitor(host) < 0))
 		goto no_locks;
 	*hostp = host;
 
@@ -260,7 +260,9 @@
 	struct nlm_rqst	*call;
 	int stat;
 
-	host = nlmsvc_lookup_host(rqstp);
+	host = nlmsvc_lookup_host(rqstp,
+				  argp->lock.caller,
+				  argp->lock.len);
 	if (host == NULL)
 		return rpc_system_err;
 
@@ -420,10 +422,6 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
-	int			vers = argp->vers;
-	int			prot = argp->proto >> 1;
-
-	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
 	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
@@ -438,21 +436,10 @@
 	/* Obtain the host pointer for this NFS server and try to
 	 * reclaim all locks we hold on this server.
 	 */
+	memset(&saddr, 0, sizeof(saddr));
 	saddr.sin_addr.s_addr = argp->addr;
+	nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
 
-	if ((argp->proto & 1)==0) {
-		if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
-			nlmclnt_recovery(host, argp->state);
-			nlm_release_host(host);
-		}
-	} else {
-		/* If we run on an NFS server, delete all locks held by the client */
-
-		if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
-			nlmsvc_free_host_resources(host);
-			nlm_release_host(host);
-		}
-	}
 	return rpc_success;
 }
 
@@ -468,7 +455,7 @@
 
         dprintk("lockd: GRANTED_RES   called\n");
 
-        nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+        nlmsvc_grant_reply(&argp->cookie, argp->status);
         return rpc_success;
 }
 
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 93c00ee..814c606 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -40,7 +40,7 @@
 
 static void nlmsvc_release_block(struct nlm_block *block);
 static void	nlmsvc_insert_block(struct nlm_block *block, unsigned long);
-static int	nlmsvc_remove_block(struct nlm_block *block);
+static void	nlmsvc_remove_block(struct nlm_block *block);
 
 static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
 static void nlmsvc_freegrantargs(struct nlm_rqst *call);
@@ -49,7 +49,7 @@
 /*
  * The list of blocked locks to retry
  */
-static struct nlm_block *	nlm_blocked;
+static LIST_HEAD(nlm_blocked);
 
 /*
  * Insert a blocked lock into the global list
@@ -57,48 +57,44 @@
 static void
 nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
 {
-	struct nlm_block **bp, *b;
+	struct nlm_block *b;
+	struct list_head *pos;
 
 	dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
-	kref_get(&block->b_count);
-	if (block->b_queued)
-		nlmsvc_remove_block(block);
-	bp = &nlm_blocked;
+	if (list_empty(&block->b_list)) {
+		kref_get(&block->b_count);
+	} else {
+		list_del_init(&block->b_list);
+	}
+
+	pos = &nlm_blocked;
 	if (when != NLM_NEVER) {
 		if ((when += jiffies) == NLM_NEVER)
 			when ++;
-		while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER)
-			bp = &b->b_next;
-	} else
-		while ((b = *bp) != 0)
-			bp = &b->b_next;
+		list_for_each(pos, &nlm_blocked) {
+			b = list_entry(pos, struct nlm_block, b_list);
+			if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
+				break;
+		}
+		/* On normal exit from the loop, pos == &nlm_blocked,
+		 * so we will be adding to the end of the list - good
+		 */
+	}
 
-	block->b_queued = 1;
+	list_add_tail(&block->b_list, pos);
 	block->b_when = when;
-	block->b_next = b;
-	*bp = block;
 }
 
 /*
  * Remove a block from the global list
  */
-static int
+static inline void
 nlmsvc_remove_block(struct nlm_block *block)
 {
-	struct nlm_block **bp, *b;
-
-	if (!block->b_queued)
-		return 1;
-	for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) {
-		if (b == block) {
-			*bp = block->b_next;
-			block->b_queued = 0;
-			nlmsvc_release_block(block);
-			return 1;
-		}
+	if (!list_empty(&block->b_list)) {
+		list_del_init(&block->b_list);
+		nlmsvc_release_block(block);
 	}
-
-	return 0;
 }
 
 /*
@@ -107,14 +103,14 @@
 static struct nlm_block *
 nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
 {
-	struct nlm_block	**head, *block;
+	struct nlm_block	*block;
 	struct file_lock	*fl;
 
 	dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
 				file, lock->fl.fl_pid,
 				(long long)lock->fl.fl_start,
 				(long long)lock->fl.fl_end, lock->fl.fl_type);
-	for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
+	list_for_each_entry(block, &nlm_blocked, b_list) {
 		fl = &block->b_call->a_args.lock.fl;
 		dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
 				block->b_file, fl->fl_pid,
@@ -143,20 +139,20 @@
  * Find a block with a given NLM cookie.
  */
 static inline struct nlm_block *
-nlmsvc_find_block(struct nlm_cookie *cookie,  struct sockaddr_in *sin)
+nlmsvc_find_block(struct nlm_cookie *cookie)
 {
 	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)
-				&& nlm_cmp_addr(sin, &block->b_host->h_addr))
-			break;
+	list_for_each_entry(block, &nlm_blocked, b_list) {
+		if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
+			goto found;
 	}
 
-	if (block != NULL)
-		kref_get(&block->b_count);
+	return NULL;
+
+found:
+	dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
+	kref_get(&block->b_count);
 	return block;
 }
 
@@ -169,6 +165,11 @@
  * request, but (as I found out later) that's because some implementations
  * do just this. Never mind the standards comittees, they support our
  * logging industries.
+ *
+ * 10 years later: I hope we can safely ignore these old and broken
+ * clients by now. Let's fix this so we can uniquely identify an incoming
+ * GRANTED_RES message by cookie, without having to rely on the client's IP
+ * address. --okir
  */
 static inline struct nlm_block *
 nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
@@ -179,7 +180,7 @@
 	struct nlm_rqst		*call = NULL;
 
 	/* Create host handle for callback */
-	host = nlmsvc_lookup_host(rqstp);
+	host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len);
 	if (host == NULL)
 		return NULL;
 
@@ -192,6 +193,8 @@
 	if (block == NULL)
 		goto failed;
 	kref_init(&block->b_count);
+	INIT_LIST_HEAD(&block->b_list);
+	INIT_LIST_HEAD(&block->b_flist);
 
 	if (!nlmsvc_setgrantargs(call, lock))
 		goto failed_free;
@@ -199,7 +202,7 @@
 	/* Set notifier function for VFS, and init args */
 	call->a_args.lock.fl.fl_flags |= FL_SLEEP;
 	call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
-	call->a_args.cookie = *cookie;	/* see above */
+	nlmclnt_next_cookie(&call->a_args.cookie);
 
 	dprintk("lockd: created block %p...\n", block);
 
@@ -210,8 +213,7 @@
 	file->f_count++;
 
 	/* Add to file's list of blocks */
-	block->b_fnext  = file->f_blocks;
-	file->f_blocks  = block;
+	list_add(&block->b_flist, &file->f_blocks);
 
 	/* Set up RPC arguments for callback */
 	block->b_call = call;
@@ -248,19 +250,13 @@
 {
 	struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
 	struct nlm_file		*file = block->b_file;
-	struct nlm_block	**bp;
 
 	dprintk("lockd: freeing block %p...\n", block);
 
-	down(&file->f_sema);
 	/* Remove block from file's list of blocks */
-	for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
-		if (*bp == block) {
-			*bp = block->b_fnext;
-			break;
-		}
-	}
-	up(&file->f_sema);
+	mutex_lock(&file->f_mutex);
+	list_del_init(&block->b_flist);
+	mutex_unlock(&file->f_mutex);
 
 	nlmsvc_freegrantargs(block->b_call);
 	nlm_release_call(block->b_call);
@@ -274,47 +270,32 @@
 		kref_put(&block->b_count, nlmsvc_free_block);
 }
 
-static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file)
+/*
+ * Loop over all blocks and delete blocks held by
+ * a matching host.
+ */
+void nlmsvc_traverse_blocks(struct nlm_host *host,
+			struct nlm_file *file,
+			nlm_host_match_fn_t match)
 {
-	struct nlm_block *block;
-
-	down(&file->f_sema);
-	for (block = file->f_blocks; block != NULL; block = block->b_fnext)
-		block->b_host->h_inuse = 1;
-	up(&file->f_sema);
-}
-
-static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
-{
-	struct nlm_block *block;
+	struct nlm_block *block, *next;
 
 restart:
-	down(&file->f_sema);
-	for (block = file->f_blocks; block != NULL; block = block->b_fnext) {
-		if (host != NULL && host != block->b_host)
+	mutex_lock(&file->f_mutex);
+	list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
+		if (!match(block->b_host, host))
 			continue;
-		if (!block->b_queued)
+		/* Do not destroy blocks that are not on
+		 * the global retry list - why? */
+		if (list_empty(&block->b_list))
 			continue;
 		kref_get(&block->b_count);
-		up(&file->f_sema);
+		mutex_unlock(&file->f_mutex);
 		nlmsvc_unlink_block(block);
 		nlmsvc_release_block(block);
 		goto restart;
 	}
-	up(&file->f_sema);
-}
-
-/*
- * Loop over all blocks and perform the action specified.
- * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
- */
-void
-nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
-{
-	if (action == NLM_ACT_MARK)
-		nlmsvc_act_mark(host, file);
-	else
-		nlmsvc_act_unlock(host, file);
+	mutex_unlock(&file->f_mutex);
 }
 
 /*
@@ -373,7 +354,7 @@
 	lock->fl.fl_flags &= ~FL_SLEEP;
 again:
 	/* Lock file against concurrent access */
-	down(&file->f_sema);
+	mutex_lock(&file->f_mutex);
 	/* Get existing block (in case client is busy-waiting) */
 	block = nlmsvc_lookup_block(file, lock);
 	if (block == NULL) {
@@ -411,10 +392,10 @@
 
 	/* If we don't have a block, create and initialize it. Then
 	 * retry because we may have slept in kmalloc. */
-	/* We have to release f_sema as nlmsvc_create_block may try to
+	/* We have to release f_mutex as nlmsvc_create_block may try to
 	 * to claim it while doing host garbage collection */
 	if (newblock == NULL) {
-		up(&file->f_sema);
+		mutex_unlock(&file->f_mutex);
 		dprintk("lockd: blocking on this lock (allocating).\n");
 		if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
 			return nlm_lck_denied_nolocks;
@@ -424,7 +405,7 @@
 	/* Append to list of blocked */
 	nlmsvc_insert_block(newblock, NLM_NEVER);
 out:
-	up(&file->f_sema);
+	mutex_unlock(&file->f_mutex);
 	nlmsvc_release_block(newblock);
 	nlmsvc_release_block(block);
 	dprintk("lockd: nlmsvc_lock returned %u\n", ret);
@@ -451,6 +432,7 @@
 				(long long)conflock->fl.fl_start,
 				(long long)conflock->fl.fl_end);
 		conflock->caller = "somehost";	/* FIXME */
+		conflock->len = strlen(conflock->caller);
 		conflock->oh.len = 0;		/* don't return OH info */
 		conflock->svid = conflock->fl.fl_pid;
 		return nlm_lck_denied;
@@ -507,9 +489,9 @@
 				(long long)lock->fl.fl_start,
 				(long long)lock->fl.fl_end);
 
-	down(&file->f_sema);
+	mutex_lock(&file->f_mutex);
 	block = nlmsvc_lookup_block(file, lock);
-	up(&file->f_sema);
+	mutex_unlock(&file->f_mutex);
 	if (block != NULL) {
 		status = nlmsvc_unlink_block(block);
 		nlmsvc_release_block(block);
@@ -527,10 +509,10 @@
 static void
 nlmsvc_notify_blocked(struct file_lock *fl)
 {
-	struct nlm_block	**bp, *block;
+	struct nlm_block	*block;
 
 	dprintk("lockd: VFS unblock notification for block %p\n", fl);
-	for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
+	list_for_each_entry(block, &nlm_blocked, b_list) {
 		if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
 			nlmsvc_insert_block(block, 0);
 			svc_wake_up(block->b_daemon);
@@ -663,17 +645,14 @@
  * block.
  */
 void
-nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status)
+nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
 {
 	struct nlm_block	*block;
-	struct nlm_file		*file;
 
-	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)))
+	dprintk("grant_reply: looking for cookie %x, s=%d \n",
+		*(unsigned int *)(cookie->data), status);
+	if (!(block = nlmsvc_find_block(cookie)))
 		return;
-	file = block->b_file;
 
 	if (block) {
 		if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
@@ -696,16 +675,19 @@
 unsigned long
 nlmsvc_retry_blocked(void)
 {
-	struct nlm_block	*block;
+	unsigned long	timeout = MAX_SCHEDULE_TIMEOUT;
+	struct nlm_block *block;
 
-	dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
-			nlm_blocked,
-			nlm_blocked? nlm_blocked->b_when : 0);
-	while ((block = nlm_blocked) != 0) {
+	while (!list_empty(&nlm_blocked)) {
+		block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
+
 		if (block->b_when == NLM_NEVER)
 			break;
-	        if (time_after(block->b_when,jiffies))
+	        if (time_after(block->b_when,jiffies)) {
+			timeout = block->b_when - jiffies;
 			break;
+		}
+
 		dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 			block, block->b_when);
 		kref_get(&block->b_count);
@@ -713,8 +695,5 @@
 		nlmsvc_release_block(block);
 	}
 
-	if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
-		return (block->b_when - jiffies);
-
-	return MAX_SCHEDULE_TIMEOUT;
+	return timeout;
 }
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index dbb66a3..75b2c81 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -66,8 +66,8 @@
 		return nlm_lck_denied_nolocks;
 
 	/* Obtain host handle */
-	if (!(host = nlmsvc_lookup_host(rqstp))
-	 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+	if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
+	 || (argp->monitor && nsm_monitor(host) < 0))
 		goto no_locks;
 	*hostp = host;
 
@@ -287,7 +287,9 @@
 	struct nlm_rqst	*call;
 	int stat;
 
-	host = nlmsvc_lookup_host(rqstp);
+	host = nlmsvc_lookup_host(rqstp,
+				  argp->lock.caller,
+				  argp->lock.len);
 	if (host == NULL)
 		return rpc_system_err;
 
@@ -449,9 +451,6 @@
 					      void	        *resp)
 {
 	struct sockaddr_in	saddr = rqstp->rq_addr;
-	int			vers = argp->vers;
-	int			prot = argp->proto >> 1;
-	struct nlm_host		*host;
 
 	dprintk("lockd: SM_NOTIFY     called\n");
 	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
@@ -466,19 +465,9 @@
 	/* Obtain the host pointer for this NFS server and try to
 	 * reclaim all locks we hold on this server.
 	 */
+	memset(&saddr, 0, sizeof(saddr));
 	saddr.sin_addr.s_addr = argp->addr;
-	if ((argp->proto & 1)==0) {
-		if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
-			nlmclnt_recovery(host, argp->state);
-			nlm_release_host(host);
-		}
-	} else {
-		/* If we run on an NFS server, delete all locks held by the client */
-		if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
-			nlmsvc_free_host_resources(host);
-			nlm_release_host(host);
-		}
-	}
+	nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
 
 	return rpc_success;
 }
@@ -495,7 +484,7 @@
 
 	dprintk("lockd: GRANTED_RES   called\n");
 
-	nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+	nlmsvc_grant_reply(&argp->cookie, argp->status);
 	return rpc_success;
 }
 
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 27288c8..b9926ce 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -85,24 +85,20 @@
 }
 
 /*
- * Traverse all shares for a given file (and host).
- * NLM_ACT_CHECK is handled by nlmsvc_inspect_file.
+ * Traverse all shares for a given file, and delete
+ * those owned by the given (type of) host
  */
-void
-nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
+void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
+		nlm_host_match_fn_t match)
 {
 	struct nlm_share	*share, **shpp;
 
 	shpp = &file->f_shares;
 	while ((share = *shpp) !=  NULL) {
-		if (action == NLM_ACT_MARK)
-			share->s_host->h_inuse = 1;
-		else if (action == NLM_ACT_UNLOCK) {
-			if (host == NULL || host == share->s_host) {
-				*shpp = share->s_next;
-				kfree(share);
-				continue;
-			}
+		if (match(share->s_host, host)) {
+			*shpp = share->s_next;
+			kfree(share);
+			continue;
 		}
 		shpp = &share->s_next;
 	}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index a92dd98f..514f5f2 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -25,9 +25,9 @@
 /*
  * Global file hash table
  */
-#define FILE_HASH_BITS		5
+#define FILE_HASH_BITS		7
 #define FILE_NRHASH		(1<<FILE_HASH_BITS)
-static struct nlm_file *	nlm_files[FILE_NRHASH];
+static struct hlist_head	nlm_files[FILE_NRHASH];
 static DEFINE_MUTEX(nlm_file_mutex);
 
 #ifdef NFSD_DEBUG
@@ -82,6 +82,7 @@
 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
 					struct nfs_fh *f)
 {
+	struct hlist_node *pos;
 	struct nlm_file	*file;
 	unsigned int	hash;
 	u32		nfserr;
@@ -93,7 +94,7 @@
 	/* Lock file table */
 	mutex_lock(&nlm_file_mutex);
 
-	for (file = nlm_files[hash]; file; file = file->f_next)
+	hlist_for_each_entry(file, pos, &nlm_files[hash], f_list)
 		if (!nfs_compare_fh(&file->f_handle, f))
 			goto found;
 
@@ -105,8 +106,9 @@
 		goto out_unlock;
 
 	memcpy(&file->f_handle, f, sizeof(struct nfs_fh));
-	file->f_hash = hash;
-	init_MUTEX(&file->f_sema);
+	mutex_init(&file->f_mutex);
+	INIT_HLIST_NODE(&file->f_list);
+	INIT_LIST_HEAD(&file->f_blocks);
 
 	/* Open the file. Note that this must not sleep for too long, else
 	 * we would lock up lockd:-) So no NFS re-exports, folks.
@@ -115,12 +117,11 @@
 	 * the file.
 	 */
 	if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) {
-		dprintk("lockd: open failed (nfserr %d)\n", ntohl(nfserr));
+		dprintk("lockd: open failed (error %d)\n", nfserr);
 		goto out_free;
 	}
 
-	file->f_next = nlm_files[hash];
-	nlm_files[hash] = file;
+	hlist_add_head(&file->f_list, &nlm_files[hash]);
 
 found:
 	dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
@@ -149,22 +150,14 @@
 static inline void
 nlm_delete_file(struct nlm_file *file)
 {
-	struct nlm_file	**fp, *f;
-
 	nlm_debug_print_file("closing file", file);
-
-	fp = nlm_files + file->f_hash;
-	while ((f = *fp) != NULL) {
-		if (f == file) {
-			*fp = file->f_next;
-			nlmsvc_ops->fclose(file->f_file);
-			kfree(file);
-			return;
-		}
-		fp = &f->f_next;
+	if (!hlist_unhashed(&file->f_list)) {
+		hlist_del(&file->f_list);
+		nlmsvc_ops->fclose(file->f_file);
+		kfree(file);
+	} else {
+		printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
 	}
-
-	printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
 }
 
 /*
@@ -172,7 +165,8 @@
  * action.
  */
 static int
-nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
+			nlm_host_match_fn_t match)
 {
 	struct inode	 *inode = nlmsvc_file_inode(file);
 	struct file_lock *fl;
@@ -186,16 +180,10 @@
 
 		/* update current lock count */
 		file->f_locks++;
-		lockhost = (struct nlm_host *) fl->fl_owner;
-		if (action == NLM_ACT_MARK)
-			lockhost->h_inuse = 1;
-		else if (action == NLM_ACT_CHECK)
-			return 1;
-		else if (action == NLM_ACT_UNLOCK) {
-			struct file_lock lock = *fl;
 
-			if (host && lockhost != host)
-				continue;
+		lockhost = (struct nlm_host *) fl->fl_owner;
+		if (match(lockhost, host)) {
+			struct file_lock lock = *fl;
 
 			lock.fl_type  = F_UNLCK;
 			lock.fl_start = 0;
@@ -213,53 +201,66 @@
 }
 
 /*
- * Operate on a single file
+ * Inspect a single file
  */
 static inline int
-nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match)
 {
-	if (action == NLM_ACT_CHECK) {
-		/* Fast path for mark and sweep garbage collection */
-		if (file->f_count || file->f_blocks || file->f_shares)
+	nlmsvc_traverse_blocks(host, file, match);
+	nlmsvc_traverse_shares(host, file, match);
+	return nlm_traverse_locks(host, file, match);
+}
+
+/*
+ * Quick check whether there are still any locks, blocks or
+ * shares on a given file.
+ */
+static inline int
+nlm_file_inuse(struct nlm_file *file)
+{
+	struct inode	 *inode = nlmsvc_file_inode(file);
+	struct file_lock *fl;
+
+	if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
+		return 1;
+
+	for (fl = inode->i_flock; fl; fl = fl->fl_next) {
+		if (fl->fl_lmops == &nlmsvc_lock_operations)
 			return 1;
-	} else {
-		nlmsvc_traverse_blocks(host, file, action);
-		nlmsvc_traverse_shares(host, file, action);
 	}
-	return nlm_traverse_locks(host, file, action);
+	file->f_locks = 0;
+	return 0;
 }
 
 /*
  * Loop over all files in the file table.
  */
 static int
-nlm_traverse_files(struct nlm_host *host, int action)
+nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
 {
-	struct nlm_file	*file, **fp;
+	struct hlist_node *pos, *next;
+	struct nlm_file	*file;
 	int i, ret = 0;
 
 	mutex_lock(&nlm_file_mutex);
 	for (i = 0; i < FILE_NRHASH; i++) {
-		fp = nlm_files + i;
-		while ((file = *fp) != NULL) {
+		hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
 			file->f_count++;
 			mutex_unlock(&nlm_file_mutex);
 
 			/* Traverse locks, blocks and shares of this file
 			 * and update file->f_locks count */
-			if (nlm_inspect_file(host, file, action))
+			if (nlm_inspect_file(host, file, match))
 				ret = 1;
 
 			mutex_lock(&nlm_file_mutex);
 			file->f_count--;
 			/* No more references to this file. Let go of it. */
-			if (!file->f_blocks && !file->f_locks
+			if (list_empty(&file->f_blocks) && !file->f_locks
 			 && !file->f_shares && !file->f_count) {
-				*fp = file->f_next;
+				hlist_del(&file->f_list);
 				nlmsvc_ops->fclose(file->f_file);
 				kfree(file);
-			} else {
-				fp = &file->f_next;
 			}
 		}
 	}
@@ -286,23 +287,54 @@
 	mutex_lock(&nlm_file_mutex);
 
 	/* If there are no more locks etc, delete the file */
-	if(--file->f_count == 0) {
-		if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
-			nlm_delete_file(file);
-	}
+	if (--file->f_count == 0 && !nlm_file_inuse(file))
+		nlm_delete_file(file);
 
 	mutex_unlock(&nlm_file_mutex);
 }
 
 /*
+ * Helpers function for resource traversal
+ *
+ * nlmsvc_mark_host:
+ *	used by the garbage collector; simply sets h_inuse.
+ *	Always returns 0.
+ *
+ * nlmsvc_same_host:
+ *	returns 1 iff the two hosts match. Used to release
+ *	all resources bound to a specific host.
+ *
+ * nlmsvc_is_client:
+ *	returns 1 iff the host is a client.
+ *	Used by nlmsvc_invalidate_all
+ */
+static int
+nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy)
+{
+	host->h_inuse = 1;
+	return 0;
+}
+
+static int
+nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other)
+{
+	return host == other;
+}
+
+static int
+nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy)
+{
+	return host->h_server;
+}
+
+/*
  * Mark all hosts that still hold resources
  */
 void
 nlmsvc_mark_resources(void)
 {
 	dprintk("lockd: nlmsvc_mark_resources\n");
-
-	nlm_traverse_files(NULL, NLM_ACT_MARK);
+	nlm_traverse_files(NULL, nlmsvc_mark_host);
 }
 
 /*
@@ -313,23 +345,25 @@
 {
 	dprintk("lockd: nlmsvc_free_host_resources\n");
 
-	if (nlm_traverse_files(host, NLM_ACT_UNLOCK))
+	if (nlm_traverse_files(host, nlmsvc_same_host)) {
 		printk(KERN_WARNING
-			"lockd: couldn't remove all locks held by %s",
+			"lockd: couldn't remove all locks held by %s\n",
 			host->h_name);
+		BUG();
+	}
 }
 
 /*
- * delete all hosts structs for clients
+ * Remove all locks held for clients
  */
 void
 nlmsvc_invalidate_all(void)
 {
-	struct nlm_host *host;
-	while ((host = nlm_find_client()) != NULL) {
-		nlmsvc_free_host_resources(host);
-		host->h_expires = 0;
-		host->h_killed = 1;
-		nlm_release_host(host);
-	}
+	/* Release all locks held by NFS clients.
+	 * Previously, the code would call
+	 * nlmsvc_free_host_resources for each client in
+	 * turn, which is about as inefficient as it gets.
+	 * Now we just do it once in nlm_traverse_files.
+	 */
+	nlm_traverse_files(NULL, nlmsvc_is_client);
 }
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 8106f3b..6e4e48c 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -10,7 +10,6 @@
  */
 
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 76b08ae..20c6f39 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -9,7 +9,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 6040864..ec1114b 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -7,8 +7,6 @@
  * NFS namespace
  */
 
-#include <linux/config.h>
-
 #include <linux/dcache.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 24e47f3..b872779 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -7,8 +7,6 @@
  * NFSv4 namespace
  */
 
-#include <linux/config.h>
-
 #include <linux/dcache.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index 1d656a6..8dfefe4 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -69,7 +69,6 @@
  *	Fabian Frederick:	Option parser rebuilt (using parser lib)
 */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index e8d4003..28659a9 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -20,7 +20,6 @@
  *   of another (see nfs_lookup())
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/init.h>
 
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index cfe141e..e13fa23 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -319,12 +319,25 @@
 
 static struct cache_head *export_table[EXPORT_HASHMAX];
 
+static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
+{
+	int i;
+
+	for (i = 0; i < fsloc->locations_count; i++) {
+		kfree(fsloc->locations[i].path);
+		kfree(fsloc->locations[i].hosts);
+	}
+	kfree(fsloc->locations);
+}
+
 static void svc_export_put(struct kref *ref)
 {
 	struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
 	dput(exp->ex_dentry);
 	mntput(exp->ex_mnt);
 	auth_domain_put(exp->ex_client);
+	kfree(exp->ex_path);
+	nfsd4_fslocs_free(&exp->ex_fslocs);
 	kfree(exp);
 }
 
@@ -386,6 +399,69 @@
 
 }
 
+#ifdef CONFIG_NFSD_V4
+
+static int
+fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
+{
+	int len;
+	int migrated, i, err;
+
+	len = qword_get(mesg, buf, PAGE_SIZE);
+	if (len != 5 || memcmp(buf, "fsloc", 5))
+		return 0;
+
+	/* listsize */
+	err = get_int(mesg, &fsloc->locations_count);
+	if (err)
+		return err;
+	if (fsloc->locations_count > MAX_FS_LOCATIONS)
+		return -EINVAL;
+	if (fsloc->locations_count == 0)
+		return 0;
+
+	fsloc->locations = kzalloc(fsloc->locations_count
+			* sizeof(struct nfsd4_fs_location), GFP_KERNEL);
+	if (!fsloc->locations)
+		return -ENOMEM;
+	for (i=0; i < fsloc->locations_count; i++) {
+		/* colon separated host list */
+		err = -EINVAL;
+		len = qword_get(mesg, buf, PAGE_SIZE);
+		if (len <= 0)
+			goto out_free_all;
+		err = -ENOMEM;
+		fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
+		if (!fsloc->locations[i].hosts)
+			goto out_free_all;
+		err = -EINVAL;
+		/* slash separated path component list */
+		len = qword_get(mesg, buf, PAGE_SIZE);
+		if (len <= 0)
+			goto out_free_all;
+		err = -ENOMEM;
+		fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
+		if (!fsloc->locations[i].path)
+			goto out_free_all;
+	}
+	/* migrated */
+	err = get_int(mesg, &migrated);
+	if (err)
+		goto out_free_all;
+	err = -EINVAL;
+	if (migrated < 0 || migrated > 1)
+		goto out_free_all;
+	fsloc->migrated = migrated;
+	return 0;
+out_free_all:
+	nfsd4_fslocs_free(fsloc);
+	return err;
+}
+
+#else /* CONFIG_NFSD_V4 */
+static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; }
+#endif
+
 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
 {
 	/* client path expiry [flags anonuid anongid fsid] */
@@ -398,6 +474,7 @@
 	int an_int;
 
 	nd.dentry = NULL;
+	exp.ex_path = NULL;
 
 	if (mesg[mlen-1] != '\n')
 		return -EINVAL;
@@ -428,6 +505,10 @@
 	exp.ex_client = dom;
 	exp.ex_mnt = nd.mnt;
 	exp.ex_dentry = nd.dentry;
+	exp.ex_path = kstrdup(buf, GFP_KERNEL);
+	err = -ENOMEM;
+	if (!exp.ex_path)
+		goto out;
 
 	/* expiry */
 	err = -EINVAL;
@@ -435,6 +516,11 @@
 	if (exp.h.expiry_time == 0)
 		goto out;
 
+	/* fs locations */
+	exp.ex_fslocs.locations = NULL;
+	exp.ex_fslocs.locations_count = 0;
+	exp.ex_fslocs.migrated = 0;
+
 	/* flags */
 	err = get_int(&mesg, &an_int);
 	if (err == -ENOENT)
@@ -460,6 +546,10 @@
 
 		err = check_export(nd.dentry->d_inode, exp.ex_flags);
 		if (err) goto out;
+
+		err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
+		if (err)
+			goto out;
 	}
 
 	expp = svc_export_lookup(&exp);
@@ -473,6 +563,7 @@
 	else
 		exp_put(expp);
  out:
+ 	kfree(exp.ex_path);
 	if (nd.dentry)
 		path_release(&nd);
  out_no_path:
@@ -482,7 +573,8 @@
 	return err;
 }
 
-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong);
+static void exp_flags(struct seq_file *m, int flag, int fsid,
+		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
 
 static int svc_export_show(struct seq_file *m,
 			   struct cache_detail *cd,
@@ -501,8 +593,8 @@
 	seq_putc(m, '(');
 	if (test_bit(CACHE_VALID, &h->flags) && 
 	    !test_bit(CACHE_NEGATIVE, &h->flags))
-		exp_flags(m, exp->ex_flags, exp->ex_fsid, 
-			  exp->ex_anon_uid, exp->ex_anon_gid);
+		exp_flags(m, exp->ex_flags, exp->ex_fsid,
+			  exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
 	seq_puts(m, ")\n");
 	return 0;
 }
@@ -524,6 +616,10 @@
 	new->ex_client = item->ex_client;
 	new->ex_dentry = dget(item->ex_dentry);
 	new->ex_mnt = mntget(item->ex_mnt);
+	new->ex_path = NULL;
+	new->ex_fslocs.locations = NULL;
+	new->ex_fslocs.locations_count = 0;
+	new->ex_fslocs.migrated = 0;
 }
 
 static void export_update(struct cache_head *cnew, struct cache_head *citem)
@@ -535,6 +631,14 @@
 	new->ex_anon_uid = item->ex_anon_uid;
 	new->ex_anon_gid = item->ex_anon_gid;
 	new->ex_fsid = item->ex_fsid;
+	new->ex_path = item->ex_path;
+	item->ex_path = NULL;
+	new->ex_fslocs.locations = item->ex_fslocs.locations;
+	item->ex_fslocs.locations = NULL;
+	new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
+	item->ex_fslocs.locations_count = 0;
+	new->ex_fslocs.migrated = item->ex_fslocs.migrated;
+	item->ex_fslocs.migrated = 0;
 }
 
 static struct cache_head *svc_export_alloc(void)
@@ -1048,30 +1152,21 @@
 exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
 	       struct cache_req *creq)
 {
-	struct svc_expkey *fsid_key;
 	struct svc_export *exp;
 	int rv;
 	u32 fsidv[2];
 
 	mk_fsid_v1(fsidv, 0);
 
-	fsid_key = exp_find_key(clp, 1, fsidv, creq);
-	if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN)
+	exp = exp_find(clp, 1, fsidv, creq);
+	if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
 		return nfserr_dropit;
-	if (!fsid_key || IS_ERR(fsid_key))
-		return nfserr_perm;
-
-	exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq);
 	if (exp == NULL)
-		rv = nfserr_perm;
+		return nfserr_perm;
 	else if (IS_ERR(exp))
-		rv = nfserrno(PTR_ERR(exp));
-	else {
-		rv = fh_compose(fhp, exp,
-				fsid_key->ek_dentry, NULL);
-		exp_put(exp);
-	}
-	cache_put(&fsid_key->h, &svc_expkey_cache);
+		return nfserrno(PTR_ERR(exp));
+	rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
+	exp_put(exp);
 	return rv;
 }
 
@@ -1158,7 +1253,8 @@
 	{ 0, {"", ""}}
 };
 
-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong)
+static void exp_flags(struct seq_file *m, int flag, int fsid,
+		uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
 {
 	int first = 0;
 	struct flags *flg;
@@ -1174,6 +1270,21 @@
 		seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
 	if (anong != (gid_t)-2 && anong != (0x10000-2))
 		seq_printf(m, "%sanongid=%d", first++?",":"", anong);
+	if (fsloc && fsloc->locations_count > 0) {
+		char *loctype = (fsloc->migrated) ? "refer" : "replicas";
+		int i;
+
+		seq_printf(m, "%s%s=", first++?",":"", loctype);
+		seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
+		seq_putc(m, '@');
+		seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
+		for (i = 1; i < fsloc->locations_count; i++) {
+			seq_putc(m, ';');
+			seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
+			seq_putc(m, '@');
+			seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
+		}
+	}
 }
 
 static int e_show(struct seq_file *m, void *p)
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index fe56b38..9187755 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -241,7 +241,7 @@
 
 	rqstp->rq_res.page_len = w;
 	while (w > 0) {
-		if (!svc_take_res_page(rqstp))
+		if (!rqstp->rq_respages[rqstp->rq_resused++])
 			return 0;
 		w -= PAGE_SIZE;
 	}
@@ -333,4 +333,5 @@
 		.vs_proc	= nfsd_acl_procedures2,
 		.vs_dispatch	= nfsd_dispatch,
 		.vs_xdrsize	= NFS3_SVC_XDRSIZE,
+		.vs_hidden	= 1,
 };
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 16e10c1..d4bdc00 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -185,7 +185,7 @@
 
 		rqstp->rq_res.page_len = w;
 		while (w > 0) {
-			if (!svc_take_res_page(rqstp))
+			if (!rqstp->rq_respages[rqstp->rq_resused++])
 				return 0;
 			w -= PAGE_SIZE;
 		}
@@ -263,5 +263,6 @@
 		.vs_proc	= nfsd_acl_procedures3,
 		.vs_dispatch	= nfsd_dispatch,
 		.vs_xdrsize	= NFS3_SVC_XDRSIZE,
+		.vs_hidden	= 1,
 };
 
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index f61142a..a5ebc7d 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -160,6 +160,7 @@
 				        struct nfsd3_readres  *resp)
 {
 	int	nfserr;
+	u32	max_blocksize = svc_max_payload(rqstp);
 
 	dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
 				SVCFH_fmt(&argp->fh),
@@ -172,15 +173,15 @@
 	 */
 
 	resp->count = argp->count;
-	if (NFSSVC_MAXBLKSIZE < resp->count)
-		resp->count = NFSSVC_MAXBLKSIZE;
+	if (max_blocksize < resp->count)
+		resp->count = max_blocksize;
 
 	svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 
 	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_read(rqstp, &resp->fh, NULL,
 				  argp->offset,
-			   	  argp->vec, argp->vlen,
+			   	  rqstp->rq_vec, argp->vlen,
 				  &resp->count);
 	if (nfserr == 0) {
 		struct inode	*inode = resp->fh.fh_dentry->d_inode;
@@ -210,7 +211,7 @@
 	resp->committed = argp->stable;
 	nfserr = nfsd_write(rqstp, &resp->fh, NULL,
 				   argp->offset,
-				   argp->vec, argp->vlen,
+				   rqstp->rq_vec, argp->vlen,
 				   argp->len,
 				   &resp->committed);
 	resp->count = argp->count;
@@ -538,15 +539,16 @@
 					   struct nfsd3_fsinfores *resp)
 {
 	int	nfserr;
+	u32	max_blocksize = svc_max_payload(rqstp);
 
 	dprintk("nfsd: FSINFO(3)   %s\n",
 				SVCFH_fmt(&argp->fh));
 
-	resp->f_rtmax  = NFSSVC_MAXBLKSIZE;
-	resp->f_rtpref = NFSSVC_MAXBLKSIZE;
+	resp->f_rtmax  = max_blocksize;
+	resp->f_rtpref = max_blocksize;
 	resp->f_rtmult = PAGE_SIZE;
-	resp->f_wtmax  = NFSSVC_MAXBLKSIZE;
-	resp->f_wtpref = NFSSVC_MAXBLKSIZE;
+	resp->f_wtmax  = max_blocksize;
+	resp->f_wtpref = max_blocksize;
 	resp->f_wtmult = PAGE_SIZE;
 	resp->f_dtpref = PAGE_SIZE;
 	resp->f_maxfilesize = ~(u32) 0;
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 243d94b..247d518 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -330,6 +330,7 @@
 {
 	unsigned int len;
 	int v,pn;
+	u32 max_blocksize = svc_max_payload(rqstp);
 
 	if (!(p = decode_fh(p, &args->fh))
 	 || !(p = xdr_decode_hyper(p, &args->offset)))
@@ -337,17 +338,16 @@
 
 	len = args->count = ntohl(*p++);
 
-	if (len > NFSSVC_MAXBLKSIZE)
-		len = NFSSVC_MAXBLKSIZE;
+	if (len > max_blocksize)
+		len = max_blocksize;
 
 	/* set up the kvec */
 	v=0;
 	while (len > 0) {
-		pn = rqstp->rq_resused;
-		svc_take_page(rqstp);
-		args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
-		args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
-		len -= args->vec[v].iov_len;
+		pn = rqstp->rq_resused++;
+		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+		rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
+		len -= rqstp->rq_vec[v].iov_len;
 		v++;
 	}
 	args->vlen = v;
@@ -359,6 +359,7 @@
 					struct nfsd3_writeargs *args)
 {
 	unsigned int len, v, hdr;
+	u32 max_blocksize = svc_max_payload(rqstp);
 
 	if (!(p = decode_fh(p, &args->fh))
 	 || !(p = xdr_decode_hyper(p, &args->offset)))
@@ -373,22 +374,22 @@
 	    rqstp->rq_arg.len - hdr < len)
 		return 0;
 
-	args->vec[0].iov_base = (void*)p;
-	args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
+	rqstp->rq_vec[0].iov_base = (void*)p;
+	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
 
-	if (len > NFSSVC_MAXBLKSIZE)
-		len = NFSSVC_MAXBLKSIZE;
+	if (len > max_blocksize)
+		len = max_blocksize;
 	v=  0;
-	while (len > args->vec[v].iov_len) {
-		len -= args->vec[v].iov_len;
+	while (len > rqstp->rq_vec[v].iov_len) {
+		len -= rqstp->rq_vec[v].iov_len;
 		v++;
-		args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
-		args->vec[v].iov_len = PAGE_SIZE;
+		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
+		rqstp->rq_vec[v].iov_len = PAGE_SIZE;
 	}
-	args->vec[v].iov_len = len;
+	rqstp->rq_vec[v].iov_len = len;
 	args->vlen = v+1;
 
-	return args->count == args->len && args->vec[0].iov_len > 0;
+	return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
 }
 
 int
@@ -446,11 +447,11 @@
 	 * This page appears in the rq_res.pages list, but as pages_len is always
 	 * 0, it won't get in the way
 	 */
-	svc_take_page(rqstp);
 	len = ntohl(*p++);
 	if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
 		return 0;
-	args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+	args->tname = new =
+		page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 	args->tlen = len;
 	/* first copy and check from the first page */
 	old = (char*)p;
@@ -522,8 +523,8 @@
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
-	svc_take_page(rqstp);
-	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+	args->buffer =
+		page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -554,8 +555,8 @@
 	if (args->count > PAGE_SIZE)
 		args->count = PAGE_SIZE;
 
-	svc_take_page(rqstp);
-	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+	args->buffer =
+		page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -565,6 +566,7 @@
 					struct nfsd3_readdirargs *args)
 {
 	int len, pn;
+	u32 max_blocksize = svc_max_payload(rqstp);
 
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
@@ -573,13 +575,12 @@
 	args->dircount = ntohl(*p++);
 	args->count    = ntohl(*p++);
 
-	len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE :
+	len = (args->count > max_blocksize) ? max_blocksize :
 						  args->count;
 	args->count = len;
 
 	while (len > 0) {
-		pn = rqstp->rq_resused;
-		svc_take_page(rqstp);
+		pn = rqstp->rq_resused++;
 		if (!args->buffer)
 			args->buffer = page_address(rqstp->rq_respages[pn]);
 		len -= PAGE_SIZE;
@@ -668,7 +669,6 @@
 		rqstp->rq_res.page_len = resp->len;
 		if (resp->len & 3) {
 			/* need to pad the tail */
-			rqstp->rq_restailpage = 0;
 			rqstp->rq_res.tail[0].iov_base = p;
 			*p = 0;
 			rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -693,7 +693,6 @@
 		rqstp->rq_res.page_len = resp->count;
 		if (resp->count & 3) {
 			/* need to pad the tail */
-			rqstp->rq_restailpage = 0;
 			rqstp->rq_res.tail[0].iov_base = p;
 			*p = 0;
 			rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
@@ -768,7 +767,6 @@
 		rqstp->rq_res.page_len = (resp->count) << 2;
 
 		/* add the 'tail' to the end of the 'head' page - page 0. */
-		rqstp->rq_restailpage = 0;
 		rqstp->rq_res.tail[0].iov_base = p;
 		*p++ = 0;		/* no more entries */
 		*p++ = htonl(resp->common.err == nfserr_eof);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index edb107e..5d94555 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -63,6 +63,8 @@
 #define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
 		| NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)
 
+#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP)
+
 #define MASK_EQUAL(mask1, mask2) \
 	( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
 
@@ -96,24 +98,26 @@
 /* XXX: modify functions to return NFS errors; they're only ever
  * used by nfs code, after all.... */
 
-static int
-mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
-{
-	u32 ignore = 0;
+/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
+ * side of being more restrictive, so the mode bit mapping below is
+ * pessimistic.  An optimistic version would be needed to handle DENY's,
+ * but we espect to coalesce all ALLOWs and DENYs before mapping to mode
+ * bits. */
 
-	if (!(flags & NFS4_ACL_DIR))
-		ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */
-	perm |= ignore;
+static void
+low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
+{
+	u32 write_mode = NFS4_WRITE_MODE;
+
+	if (flags & NFS4_ACL_DIR)
+		write_mode |= NFS4_ACE_DELETE_CHILD;
 	*mode = 0;
 	if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
 		*mode |= ACL_READ;
-	if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE)
+	if ((perm & write_mode) == write_mode)
 		*mode |= ACL_WRITE;
 	if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
 		*mode |= ACL_EXECUTE;
-	if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags)))
-		return -EINVAL;
-	return 0;
 }
 
 struct ace_container {
@@ -338,38 +342,6 @@
 	return;
 }
 
-static int
-write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
-		struct posix_acl_entry **pace, short tag, unsigned int flags)
-{
-	struct posix_acl_entry *this = *pace;
-
-	if (*pace == pacl->a_entries + pacl->a_count)
-		return -EINVAL; /* fell off the end */
-	(*pace)++;
-	this->e_tag = tag;
-	if (tag == ACL_USER_OBJ)
-		flags |= NFS4_ACL_OWNER;
-	if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags))
-		return -EINVAL;
-	this->e_id = (tag == ACL_USER || tag == ACL_GROUP ?
-			ace->who : ACL_UNDEFINED_ID);
-	return 0;
-}
-
-static struct nfs4_ace *
-get_next_v4_ace(struct list_head **p, struct list_head *head)
-{
-	struct nfs4_ace *ace;
-
-	*p = (*p)->next;
-	if (*p == head)
-		return NULL;
-	ace = list_entry(*p, struct nfs4_ace, l_ace);
-
-	return ace;
-}
-
 int
 nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
 		struct posix_acl **dpacl, unsigned int flags)
@@ -385,42 +357,23 @@
 		goto out;
 
 	error = nfs4_acl_split(acl, dacl);
-	if (error < 0)
+	if (error)
 		goto out_acl;
 
-	if (pacl != NULL) {
-		if (acl->naces == 0) {
-			error = -ENODATA;
-			goto try_dpacl;
-		}
-
-		*pacl = _nfsv4_to_posix_one(acl, flags);
-		if (IS_ERR(*pacl)) {
-			error = PTR_ERR(*pacl);
-			*pacl = NULL;
-			goto out_acl;
-		}
+	*pacl = _nfsv4_to_posix_one(acl, flags);
+	if (IS_ERR(*pacl)) {
+		error = PTR_ERR(*pacl);
+		*pacl = NULL;
+		goto out_acl;
 	}
 
-try_dpacl:
-	if (dpacl != NULL) {
-		if (dacl->naces == 0) {
-			if (pacl == NULL || *pacl == NULL)
-				error = -ENODATA;
-			goto out_acl;
-		}
-
-		error = 0;
-		*dpacl = _nfsv4_to_posix_one(dacl, flags);
-		if (IS_ERR(*dpacl)) {
-			error = PTR_ERR(*dpacl);
-			*dpacl = NULL;
-			goto out_acl;
-		}
+	*dpacl = _nfsv4_to_posix_one(dacl, flags);
+	if (IS_ERR(*dpacl)) {
+		error = PTR_ERR(*dpacl);
+		*dpacl = NULL;
 	}
-
 out_acl:
-	if (error && pacl) {
+	if (error) {
 		posix_acl_release(*pacl);
 		*pacl = NULL;
 	}
@@ -429,349 +382,311 @@
 	return error;
 }
 
-static int
-same_who(struct nfs4_ace *a, struct nfs4_ace *b)
-{
-	return a->whotype == b->whotype &&
-		(a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who);
-}
+/*
+ * While processing the NFSv4 ACE, this maintains bitmasks representing
+ * which permission bits have been allowed and which denied to a given
+ * entity: */
+struct posix_ace_state {
+	u32 allow;
+	u32 deny;
+};
+
+struct posix_user_ace_state {
+	uid_t uid;
+	struct posix_ace_state perms;
+};
+
+struct posix_ace_state_array {
+	int n;
+	struct posix_user_ace_state aces[];
+};
+
+/*
+ * While processing the NFSv4 ACE, this maintains the partial permissions
+ * calculated so far: */
+
+struct posix_acl_state {
+	struct posix_ace_state owner;
+	struct posix_ace_state group;
+	struct posix_ace_state other;
+	struct posix_ace_state everyone;
+	struct posix_ace_state mask; /* Deny unused in this case */
+	struct posix_ace_state_array *users;
+	struct posix_ace_state_array *groups;
+};
 
 static int
-complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny,
-		unsigned int flags)
+init_state(struct posix_acl_state *state, int cnt)
 {
-	int ignore = 0;
-	if (!(flags & NFS4_ACL_DIR))
-		ignore |= NFS4_ACE_DELETE_CHILD;
-	return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags),
-			  ignore|deny->access_mask) &&
-		allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
-		deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
-		allow->flag == deny->flag &&
-		same_who(allow, deny);
+	int alloc;
+
+	memset(state, 0, sizeof(struct posix_acl_state));
+	/*
+	 * In the worst case, each individual acl could be for a distinct
+	 * named user or group, but we don't no which, so we allocate
+	 * enough space for either:
+	 */
+	alloc = sizeof(struct posix_ace_state_array)
+		+ cnt*sizeof(struct posix_ace_state);
+	state->users = kzalloc(alloc, GFP_KERNEL);
+	if (!state->users)
+		return -ENOMEM;
+	state->groups = kzalloc(alloc, GFP_KERNEL);
+	if (!state->groups) {
+		kfree(state->users);
+		return -ENOMEM;
+	}
+	return 0;
 }
 
-static inline int
-user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
-		struct posix_acl *pacl, struct posix_acl_entry **pace,
-		unsigned int flags)
-{
-	int error = -EINVAL;
-	struct nfs4_ace *ace, *ace2;
-
-	ace = get_next_v4_ace(p, &n4acl->ace_head);
-	if (ace == NULL)
-		goto out;
-	if (ace2type(ace) != ACL_USER_OBJ)
-		goto out;
-	error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags);
-	if (error < 0)
-		goto out;
-	error = -EINVAL;
-	ace2 = get_next_v4_ace(p, &n4acl->ace_head);
-	if (ace2 == NULL)
-		goto out;
-	if (!complementary_ace_pair(ace, ace2, flags))
-		goto out;
-	error = 0;
-out:
-	return error;
+static void
+free_state(struct posix_acl_state *state) {
+	kfree(state->users);
+	kfree(state->groups);
 }
 
-static inline int
-users_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
-		struct nfs4_ace **mask_ace,
-		struct posix_acl *pacl, struct posix_acl_entry **pace,
-		unsigned int flags)
+static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
 {
-	int error = -EINVAL;
-	struct nfs4_ace *ace, *ace2;
-
-	ace = get_next_v4_ace(p, &n4acl->ace_head);
-	if (ace == NULL)
-		goto out;
-	while (ace2type(ace) == ACL_USER) {
-		if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
-			goto out;
-		if (*mask_ace &&
-			!MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
-			goto out;
-		*mask_ace = ace;
-		ace = get_next_v4_ace(p, &n4acl->ace_head);
-		if (ace == NULL)
-			goto out;
-		if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
-			goto out;
-		error = write_pace(ace, pacl, pace, ACL_USER, flags);
-		if (error < 0)
-			goto out;
-		error = -EINVAL;
-		ace2 = get_next_v4_ace(p, &n4acl->ace_head);
-		if (ace2 == NULL)
-			goto out;
-		if (!complementary_ace_pair(ace, ace2, flags))
-			goto out;
-		if ((*mask_ace)->flag != ace2->flag ||
-				!same_who(*mask_ace, ace2))
-			goto out;
-		ace = get_next_v4_ace(p, &n4acl->ace_head);
-		if (ace == NULL)
-			goto out;
-	}
-	error = 0;
-out:
-	return error;
+	state->mask.allow |= astate->allow;
 }
 
-static inline int
-group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
-		struct nfs4_ace **mask_ace,
-		struct posix_acl *pacl, struct posix_acl_entry **pace,
-		unsigned int flags)
+/*
+ * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS,
+ * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate
+ * to traditional read/write/execute permissions.
+ *
+ * It's problematic to reject acls that use certain mode bits, because it
+ * places the burden on users to learn the rules about which bits one
+ * particular server sets, without giving the user a lot of help--we return an
+ * error that could mean any number of different things.  To make matters
+ * worse, the problematic bits might be introduced by some application that's
+ * automatically mapping from some other acl model.
+ *
+ * So wherever possible we accept anything, possibly erring on the side of
+ * denying more permissions than necessary.
+ *
+ * However we do reject *explicit* DENY's of a few bits representing
+ * permissions we could never deny:
+ */
+
+static inline int check_deny(u32 mask, int isowner)
 {
-	int error = -EINVAL;
-	struct nfs4_ace *ace, *ace2;
-	struct ace_container *ac;
-	struct list_head group_l;
-
-	INIT_LIST_HEAD(&group_l);
-	ace = list_entry(*p, struct nfs4_ace, l_ace);
-
-	/* group owner (mask and allow aces) */
-
-	if (pacl->a_count != 3) {
-		/* then the group owner should be preceded by mask */
-		if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
-			goto out;
-		if (*mask_ace &&
-			!MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
-			goto out;
-		*mask_ace = ace;
-		ace = get_next_v4_ace(p, &n4acl->ace_head);
-		if (ace == NULL)
-			goto out;
-
-		if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace))
-			goto out;
-	}
-
-	if (ace2type(ace) != ACL_GROUP_OBJ)
-		goto out;
-
-	ac = kmalloc(sizeof(*ac), GFP_KERNEL);
-	error = -ENOMEM;
-	if (ac == NULL)
-		goto out;
-	ac->ace = ace;
-	list_add_tail(&ac->ace_l, &group_l);
-
-	error = -EINVAL;
-	if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
-		goto out;
-
-	error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags);
-	if (error < 0)
-		goto out;
-
-	error = -EINVAL;
-	ace = get_next_v4_ace(p, &n4acl->ace_head);
-	if (ace == NULL)
-		goto out;
-
-	/* groups (mask and allow aces) */
-
-	while (ace2type(ace) == ACL_GROUP) {
-		if (*mask_ace == NULL)
-			goto out;
-
-		if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
-			!MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
-			goto out;
-		*mask_ace = ace;
-
-		ace = get_next_v4_ace(p, &n4acl->ace_head);
-		if (ace == NULL)
-			goto out;
-		ac = kmalloc(sizeof(*ac), GFP_KERNEL);
-		error = -ENOMEM;
-		if (ac == NULL)
-			goto out;
-		error = -EINVAL;
-		if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
-				!same_who(ace, *mask_ace))
-			goto out;
-
-		ac->ace = ace;
-		list_add_tail(&ac->ace_l, &group_l);
-
-		error = write_pace(ace, pacl, pace, ACL_GROUP, flags);
-		if (error < 0)
-			goto out;
-		error = -EINVAL;
-		ace = get_next_v4_ace(p, &n4acl->ace_head);
-		if (ace == NULL)
-			goto out;
-	}
-
-	/* group owner (deny ace) */
-
-	if (ace2type(ace) != ACL_GROUP_OBJ)
-		goto out;
-	ac = list_entry(group_l.next, struct ace_container, ace_l);
-	ace2 = ac->ace;
-	if (!complementary_ace_pair(ace2, ace, flags))
-		goto out;
-	list_del(group_l.next);
-	kfree(ac);
-
-	/* groups (deny aces) */
-
-	while (!list_empty(&group_l)) {
-		ace = get_next_v4_ace(p, &n4acl->ace_head);
-		if (ace == NULL)
-			goto out;
-		if (ace2type(ace) != ACL_GROUP)
-			goto out;
-		ac = list_entry(group_l.next, struct ace_container, ace_l);
-		ace2 = ac->ace;
-		if (!complementary_ace_pair(ace2, ace, flags))
-			goto out;
-		list_del(group_l.next);
-		kfree(ac);
-	}
-
-	ace = get_next_v4_ace(p, &n4acl->ace_head);
-	if (ace == NULL)
-		goto out;
-	if (ace2type(ace) != ACL_OTHER)
-		goto out;
-	error = 0;
-out:
-	while (!list_empty(&group_l)) {
-		ac = list_entry(group_l.next, struct ace_container, ace_l);
-		list_del(group_l.next);
-		kfree(ac);
-	}
-	return error;
+	if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL))
+		return -EINVAL;
+	if (!isowner)
+		return 0;
+	if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL))
+		return -EINVAL;
+	return 0;
 }
 
-static inline int
-mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
-		struct nfs4_ace **mask_ace,
-		struct posix_acl *pacl, struct posix_acl_entry **pace,
-		unsigned int flags)
+static struct posix_acl *
+posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
 {
-	int error = -EINVAL;
-	struct nfs4_ace *ace;
+	struct posix_acl_entry *pace;
+	struct posix_acl *pacl;
+	int nace;
+	int i, error = 0;
 
-	ace = list_entry(*p, struct nfs4_ace, l_ace);
-	if (pacl->a_count != 3) {
-		if (*mask_ace == NULL)
-			goto out;
-		(*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags);
-		write_pace(*mask_ace, pacl, pace, ACL_MASK, flags);
+	nace = 4 + state->users->n + state->groups->n;
+	pacl = posix_acl_alloc(nace, GFP_KERNEL);
+	if (!pacl)
+		return ERR_PTR(-ENOMEM);
+
+	pace = pacl->a_entries;
+	pace->e_tag = ACL_USER_OBJ;
+	error = check_deny(state->owner.deny, 1);
+	if (error)
+		goto out_err;
+	low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
+	pace->e_id = ACL_UNDEFINED_ID;
+
+	for (i=0; i < state->users->n; i++) {
+		pace++;
+		pace->e_tag = ACL_USER;
+		error = check_deny(state->users->aces[i].perms.deny, 0);
+		if (error)
+			goto out_err;
+		low_mode_from_nfs4(state->users->aces[i].perms.allow,
+					&pace->e_perm, flags);
+		pace->e_id = state->users->aces[i].uid;
+		add_to_mask(state, &state->users->aces[i].perms);
 	}
-	error = 0;
-out:
-	return error;
+
+	pace++;
+	pace->e_tag = ACL_GROUP_OBJ;
+	error = check_deny(state->group.deny, 0);
+	if (error)
+		goto out_err;
+	low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
+	pace->e_id = ACL_UNDEFINED_ID;
+	add_to_mask(state, &state->group);
+
+	for (i=0; i < state->groups->n; i++) {
+		pace++;
+		pace->e_tag = ACL_GROUP;
+		error = check_deny(state->groups->aces[i].perms.deny, 0);
+		if (error)
+			goto out_err;
+		low_mode_from_nfs4(state->groups->aces[i].perms.allow,
+					&pace->e_perm, flags);
+		pace->e_id = state->groups->aces[i].uid;
+		add_to_mask(state, &state->groups->aces[i].perms);
+	}
+
+	pace++;
+	pace->e_tag = ACL_MASK;
+	low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
+	pace->e_id = ACL_UNDEFINED_ID;
+
+	pace++;
+	pace->e_tag = ACL_OTHER;
+	error = check_deny(state->other.deny, 0);
+	if (error)
+		goto out_err;
+	low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
+	pace->e_id = ACL_UNDEFINED_ID;
+
+	return pacl;
+out_err:
+	posix_acl_release(pacl);
+	return ERR_PTR(error);
 }
 
-static inline int
-other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
-		struct posix_acl *pacl, struct posix_acl_entry **pace,
-		unsigned int flags)
+static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
 {
-	int error = -EINVAL;
-	struct nfs4_ace *ace, *ace2;
-
-	ace = list_entry(*p, struct nfs4_ace, l_ace);
-	if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
-		goto out;
-	error = write_pace(ace, pacl, pace, ACL_OTHER, flags);
-	if (error < 0)
-		goto out;
-	error = -EINVAL;
-	ace2 = get_next_v4_ace(p, &n4acl->ace_head);
-	if (ace2 == NULL)
-		goto out;
-	if (!complementary_ace_pair(ace, ace2, flags))
-		goto out;
-	error = 0;
-out:
-	return error;
+	/* Allow all bits in the mask not already denied: */
+	astate->allow |= mask & ~astate->deny;
 }
 
-static int
-calculate_posix_ace_count(struct nfs4_acl *n4acl)
+static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
 {
-	if (n4acl->naces == 6) /* owner, owner group, and other only */
-		return 3;
-	else { /* Otherwise there must be a mask entry. */
-		/* Also, the remaining entries are for named users and
-		 * groups, and come in threes (mask, allow, deny): */
-		if (n4acl->naces < 7)
-			return -EINVAL;
-		if ((n4acl->naces - 7) % 3)
-			return -EINVAL;
-		return 4 + (n4acl->naces - 7)/3;
+	/* Deny all bits in the mask not already allowed: */
+	astate->deny |= mask & ~astate->allow;
+}
+
+static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid)
+{
+	int i;
+
+	for (i = 0; i < a->n; i++)
+		if (a->aces[i].uid == uid)
+			return i;
+	/* Not found: */
+	a->n++;
+	a->aces[i].uid = uid;
+	a->aces[i].perms.allow = state->everyone.allow;
+	a->aces[i].perms.deny  = state->everyone.deny;
+
+	return i;
+}
+
+static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
+{
+	int i;
+
+	for (i=0; i < a->n; i++)
+		deny_bits(&a->aces[i].perms, mask);
+}
+
+static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
+{
+	int i;
+
+	for (i=0; i < a->n; i++)
+		allow_bits(&a->aces[i].perms, mask);
+}
+
+static void process_one_v4_ace(struct posix_acl_state *state,
+				struct nfs4_ace *ace)
+{
+	u32 mask = ace->access_mask;
+	int i;
+
+	switch (ace2type(ace)) {
+	case ACL_USER_OBJ:
+		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+			allow_bits(&state->owner, mask);
+		} else {
+			deny_bits(&state->owner, mask);
+		}
+		break;
+	case ACL_USER:
+		i = find_uid(state, state->users, ace->who);
+		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+			allow_bits(&state->users->aces[i].perms, mask);
+		} else {
+			deny_bits(&state->users->aces[i].perms, mask);
+			mask = state->users->aces[i].perms.deny;
+			deny_bits(&state->owner, mask);
+		}
+		break;
+	case ACL_GROUP_OBJ:
+		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+			allow_bits(&state->group, mask);
+		} else {
+			deny_bits(&state->group, mask);
+			mask = state->group.deny;
+			deny_bits(&state->owner, mask);
+			deny_bits(&state->everyone, mask);
+			deny_bits_array(state->users, mask);
+			deny_bits_array(state->groups, mask);
+		}
+		break;
+	case ACL_GROUP:
+		i = find_uid(state, state->groups, ace->who);
+		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+			allow_bits(&state->groups->aces[i].perms, mask);
+		} else {
+			deny_bits(&state->groups->aces[i].perms, mask);
+			mask = state->groups->aces[i].perms.deny;
+			deny_bits(&state->owner, mask);
+			deny_bits(&state->group, mask);
+			deny_bits(&state->everyone, mask);
+			deny_bits_array(state->users, mask);
+			deny_bits_array(state->groups, mask);
+		}
+		break;
+	case ACL_OTHER:
+		if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+			allow_bits(&state->owner, mask);
+			allow_bits(&state->group, mask);
+			allow_bits(&state->other, mask);
+			allow_bits(&state->everyone, mask);
+			allow_bits_array(state->users, mask);
+			allow_bits_array(state->groups, mask);
+		} else {
+			deny_bits(&state->owner, mask);
+			deny_bits(&state->group, mask);
+			deny_bits(&state->other, mask);
+			deny_bits(&state->everyone, mask);
+			deny_bits_array(state->users, mask);
+			deny_bits_array(state->groups, mask);
+		}
 	}
 }
 
-
 static struct posix_acl *
 _nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags)
 {
+	struct posix_acl_state state;
 	struct posix_acl *pacl;
-	int error = -EINVAL, nace = 0;
-	struct list_head *p;
-	struct nfs4_ace *mask_ace = NULL;
-	struct posix_acl_entry *pace;
+	struct nfs4_ace *ace;
+	int ret;
 
-	nace = calculate_posix_ace_count(n4acl);
-	if (nace < 0)
-		goto out_err;
+	ret = init_state(&state, n4acl->naces);
+	if (ret)
+		return ERR_PTR(ret);
 
-	pacl = posix_acl_alloc(nace, GFP_KERNEL);
-	error = -ENOMEM;
-	if (pacl == NULL)
-		goto out_err;
+	list_for_each_entry(ace, &n4acl->ace_head, l_ace)
+		process_one_v4_ace(&state, ace);
 
-	pace = &pacl->a_entries[0];
-	p = &n4acl->ace_head;
+	pacl = posix_state_to_acl(&state, flags);
 
-	error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags);
-	if (error)
-		goto out_acl;
+	free_state(&state);
 
-	error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
-	if (error)
-		goto out_acl;
-
-	error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
-						flags);
-	if (error)
-		goto out_acl;
-
-	error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
-	if (error)
-		goto out_acl;
-	error = other_from_v4(n4acl, &p, pacl, &pace, flags);
-	if (error)
-		goto out_acl;
-
-	error = -EINVAL;
-	if (p->next != &n4acl->ace_head)
-		goto out_acl;
-	if (pace != pacl->a_entries + pacl->a_count)
-		goto out_acl;
-
-	sort_pacl(pacl);
-
-	return pacl;
-out_acl:
-	posix_acl_release(pacl);
-out_err:
-	pacl = ERR_PTR(error);
+	if (!IS_ERR(pacl))
+		sort_pacl(pacl);
 	return pacl;
 }
 
@@ -785,22 +700,41 @@
 	list_for_each_safe(h, n, &acl->ace_head) {
 		ace = list_entry(h, struct nfs4_ace, l_ace);
 
-		if ((ace->flag & NFS4_INHERITANCE_FLAGS)
-				!= NFS4_INHERITANCE_FLAGS)
+		if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
+		    ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+			return -EINVAL;
+
+		if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
+			return -EINVAL;
+
+		switch (ace->flag & NFS4_INHERITANCE_FLAGS) {
+		case 0:
+			/* Leave this ace in the effective acl: */
 			continue;
-
-		error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+		case NFS4_INHERITANCE_FLAGS:
+			/* Add this ace to the default acl and remove it
+			 * from the effective acl: */
+			error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
 				ace->access_mask, ace->whotype, ace->who);
-		if (error < 0)
-			goto out;
-
-		list_del(h);
-		kfree(ace);
-		acl->naces--;
+			if (error)
+				return error;
+			list_del(h);
+			kfree(ace);
+			acl->naces--;
+			break;
+		case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE:
+			/* Add this ace to the default, but leave it in
+			 * the effective acl as well: */
+			error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+				ace->access_mask, ace->whotype, ace->who);
+			if (error)
+				return error;
+			break;
+		default:
+			return -EINVAL;
+		}
 	}
-
-out:
-	return error;
+	return 0;
 }
 
 static short
@@ -930,23 +864,6 @@
 	return -1;
 }
 
-static inline int
-match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
-{
-	switch (ace->whotype) {
-		case NFS4_ACL_WHO_NAMED:
-			return who == ace->who;
-		case NFS4_ACL_WHO_OWNER:
-			return who == owner;
-		case NFS4_ACL_WHO_GROUP:
-			return who == group;
-		case NFS4_ACL_WHO_EVERYONE:
-			return 1;
-		default:
-			return 0;
-	}
-}
-
 EXPORT_SYMBOL(nfs4_acl_new);
 EXPORT_SYMBOL(nfs4_acl_free);
 EXPORT_SYMBOL(nfs4_acl_add_ace);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 15ded7a..8333db1 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -646,7 +646,7 @@
 	*p++ = nfssvc_boot.tv_usec;
 
 	status =  nfsd_write(rqstp, current_fh, filp, write->wr_offset,
-			write->wr_vec, write->wr_vlen, write->wr_buflen,
+			rqstp->rq_vec, write->wr_vlen, write->wr_buflen,
 			&write->wr_how_written);
 	if (filp)
 		fput(filp);
@@ -802,13 +802,29 @@
 		* SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
 		* require a valid current filehandle
 		*/
-		if ((!current_fh->fh_dentry) &&
-		   !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
-		   (op->opnum == OP_SETCLIENTID) ||
-		   (op->opnum == OP_SETCLIENTID_CONFIRM) ||
-		   (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) ||
-		   (op->opnum == OP_RELEASE_LOCKOWNER))) {
-			op->status = nfserr_nofilehandle;
+		if (!current_fh->fh_dentry) {
+			if (!((op->opnum == OP_PUTFH) ||
+			      (op->opnum == OP_PUTROOTFH) ||
+			      (op->opnum == OP_SETCLIENTID) ||
+			      (op->opnum == OP_SETCLIENTID_CONFIRM) ||
+			      (op->opnum == OP_RENEW) ||
+			      (op->opnum == OP_RESTOREFH) ||
+			      (op->opnum == OP_RELEASE_LOCKOWNER))) {
+				op->status = nfserr_nofilehandle;
+				goto encode_op;
+			}
+		}
+		/* Check must be done at start of each operation, except
+		 * for GETATTR and ops not listed as returning NFS4ERR_MOVED
+		 */
+		else if (current_fh->fh_export->ex_fslocs.migrated &&
+			 !((op->opnum == OP_GETATTR) ||
+			   (op->opnum == OP_PUTROOTFH) ||
+			   (op->opnum == OP_PUTPUBFH) ||
+			   (op->opnum == OP_RENEW) ||
+			   (op->opnum == OP_SETCLIENTID) ||
+			   (op->opnum == OP_RELEASE_LOCKOWNER))) {
+			op->status = nfserr_moved;
 			goto encode_op;
 		}
 		switch (op->opnum) {
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5be0043..41fc241 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -60,6 +60,14 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
+/*
+ * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
+ * directory in order to indicate to the client that a filesystem boundary is present
+ * We use a fixed fsid for a referral
+ */
+#define NFS4_REFERRAL_FSID_MAJOR	0x8000000ULL
+#define NFS4_REFERRAL_FSID_MINOR	0x8000000ULL
+
 static int
 check_filename(char *str, int len, int err)
 {
@@ -926,26 +934,26 @@
 		printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__); 
 		goto xdr_error;
 	}
-	write->wr_vec[0].iov_base = p;
-	write->wr_vec[0].iov_len = avail;
+	argp->rqstp->rq_vec[0].iov_base = p;
+	argp->rqstp->rq_vec[0].iov_len = avail;
 	v = 0;
 	len = write->wr_buflen;
-	while (len > write->wr_vec[v].iov_len) {
-		len -= write->wr_vec[v].iov_len;
+	while (len > argp->rqstp->rq_vec[v].iov_len) {
+		len -= argp->rqstp->rq_vec[v].iov_len;
 		v++;
-		write->wr_vec[v].iov_base = page_address(argp->pagelist[0]);
+		argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]);
 		argp->pagelist++;
 		if (argp->pagelen >= PAGE_SIZE) {
-			write->wr_vec[v].iov_len = PAGE_SIZE;
+			argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE;
 			argp->pagelen -= PAGE_SIZE;
 		} else {
-			write->wr_vec[v].iov_len = argp->pagelen;
+			argp->rqstp->rq_vec[v].iov_len = argp->pagelen;
 			argp->pagelen -= len;
 		}
 	}
-	argp->end = (u32*) (write->wr_vec[v].iov_base + write->wr_vec[v].iov_len);
-	argp->p = (u32*)  (write->wr_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
-	write->wr_vec[v].iov_len = len;
+	argp->end = (u32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len);
+	argp->p = (u32*)  (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
+	argp->rqstp->rq_vec[v].iov_len = len;
 	write->wr_vlen = v+1;
 
 	DECODE_TAIL;
@@ -1223,6 +1231,119 @@
  			stateowner->so_replay.rp_buflen); 	\
 	} } while (0);
 
+/* Encode as an array of strings the string given with components
+ * seperated @sep.
+ */
+static int nfsd4_encode_components(char sep, char *components,
+				   u32 **pp, int *buflen)
+{
+	u32 *p = *pp;
+	u32 *countp = p;
+	int strlen, count=0;
+	char *str, *end;
+
+	dprintk("nfsd4_encode_components(%s)\n", components);
+	if ((*buflen -= 4) < 0)
+		return nfserr_resource;
+	WRITE32(0); /* We will fill this in with @count later */
+	end = str = components;
+	while (*end) {
+		for (; *end && (*end != sep); end++)
+			; /* Point to end of component */
+		strlen = end - str;
+		if (strlen) {
+			if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)
+				return nfserr_resource;
+			WRITE32(strlen);
+			WRITEMEM(str, strlen);
+			count++;
+		}
+		else
+			end++;
+		str = end;
+	}
+	*pp = p;
+	p = countp;
+	WRITE32(count);
+	return 0;
+}
+
+/*
+ * encode a location element of a fs_locations structure
+ */
+static int nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
+				    u32 **pp, int *buflen)
+{
+	int status;
+	u32 *p = *pp;
+
+	status = nfsd4_encode_components(':', location->hosts, &p, buflen);
+	if (status)
+		return status;
+	status = nfsd4_encode_components('/', location->path, &p, buflen);
+	if (status)
+		return status;
+	*pp = p;
+	return 0;
+}
+
+/*
+ * Return the path to an export point in the pseudo filesystem namespace
+ * Returned string is safe to use as long as the caller holds a reference
+ * to @exp.
+ */
+static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp)
+{
+	struct svc_fh tmp_fh;
+	char *path, *rootpath;
+	int stat;
+
+	fh_init(&tmp_fh, NFS4_FHSIZE);
+	stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle);
+	if (stat)
+		return ERR_PTR(stat);
+	rootpath = tmp_fh.fh_export->ex_path;
+
+	path = exp->ex_path;
+
+	if (strncmp(path, rootpath, strlen(rootpath))) {
+		printk("nfsd: fs_locations failed;"
+			"%s is not contained in %s\n", path, rootpath);
+		return ERR_PTR(-EOPNOTSUPP);
+	}
+
+	return path + strlen(rootpath);
+}
+
+/*
+ *  encode a fs_locations structure
+ */
+static int nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
+				     struct svc_export *exp,
+				     u32 **pp, int *buflen)
+{
+	int status, i;
+	u32 *p = *pp;
+	struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
+	char *root = nfsd4_path(rqstp, exp);
+
+	if (IS_ERR(root))
+		return PTR_ERR(root);
+	status = nfsd4_encode_components('/', root, &p, buflen);
+	if (status)
+		return status;
+	if ((*buflen -= 4) < 0)
+		return nfserr_resource;
+	WRITE32(fslocs->locations_count);
+	for (i=0; i<fslocs->locations_count; i++) {
+		status = nfsd4_encode_fs_location4(&fslocs->locations[i],
+						   &p, buflen);
+		if (status)
+			return status;
+	}
+	*pp = p;
+	return 0;
+}
 
 static u32 nfs4_ftypes[16] = {
         NF4BAD,  NF4FIFO, NF4CHR, NF4BAD,
@@ -1272,6 +1393,25 @@
 	return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
 }
 
+#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
+			      FATTR4_WORD0_RDATTR_ERROR)
+#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+
+static int fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+{
+	/* As per referral draft:  */
+	if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
+	    *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
+		if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
+	            *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
+			*rdattr_err = NFSERR_MOVED;
+		else
+			return nfserr_moved;
+	}
+	*bmval0 &= WORD0_ABSENT_FS_ATTRS;
+	*bmval1 &= WORD1_ABSENT_FS_ATTRS;
+	return 0;
+}
 
 /*
  * Note: @fhp can be NULL; in this case, we might have to compose the filehandle
@@ -1294,6 +1434,7 @@
 	u32 *attrlenp;
 	u32 dummy;
 	u64 dummy64;
+	u32 rdattr_err = 0;
 	u32 *p = buffer;
 	int status;
 	int aclsupport = 0;
@@ -1303,6 +1444,12 @@
 	BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
 	BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
 
+	if (exp->ex_fslocs.migrated) {
+		status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+		if (status)
+			goto out;
+	}
+
 	status = vfs_getattr(exp->ex_mnt, dentry, &stat);
 	if (status)
 		goto out_nfserr;
@@ -1334,6 +1481,11 @@
 				goto out_nfserr;
 		}
 	}
+	if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
+		if (exp->ex_fslocs.locations == NULL) {
+			bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
+		}
+	}
 	if ((buflen -= 16) < 0)
 		goto out_resource;
 
@@ -1343,12 +1495,15 @@
 	attrlenp = p++;                /* to be backfilled later */
 
 	if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
+		u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
 		if ((buflen -= 12) < 0)
 			goto out_resource;
+		if (!aclsupport)
+			word0 &= ~FATTR4_WORD0_ACL;
+		if (!exp->ex_fslocs.locations)
+			word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
 		WRITE32(2);
-		WRITE32(aclsupport ?
-			NFSD_SUPPORTED_ATTRS_WORD0 :
-			NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL);
+		WRITE32(word0);
 		WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
 	}
 	if (bmval0 & FATTR4_WORD0_TYPE) {
@@ -1402,7 +1557,10 @@
 	if (bmval0 & FATTR4_WORD0_FSID) {
 		if ((buflen -= 16) < 0)
 			goto out_resource;
-		if (is_fsid(fhp, rqstp->rq_reffh)) {
+		if (exp->ex_fslocs.migrated) {
+			WRITE64(NFS4_REFERRAL_FSID_MAJOR);
+			WRITE64(NFS4_REFERRAL_FSID_MINOR);
+		} else if (is_fsid(fhp, rqstp->rq_reffh)) {
 			WRITE64((u64)exp->ex_fsid);
 			WRITE64((u64)0);
 		} else {
@@ -1425,7 +1583,7 @@
 	if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
 		if ((buflen -= 4) < 0)
 			goto out_resource;
-		WRITE32(0);
+		WRITE32(rdattr_err);
 	}
 	if (bmval0 & FATTR4_WORD0_ACL) {
 		struct nfs4_ace *ace;
@@ -1513,6 +1671,13 @@
 			goto out_resource;
 		WRITE64((u64) statfs.f_files);
 	}
+	if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
+		status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
+		if (status == nfserr_resource)
+			goto out_resource;
+		if (status)
+			goto out;
+	}
 	if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
 		if ((buflen -= 4) < 0)
 			goto out_resource;
@@ -1536,12 +1701,12 @@
 	if (bmval0 & FATTR4_WORD0_MAXREAD) {
 		if ((buflen -= 8) < 0)
 			goto out_resource;
-		WRITE64((u64) NFSSVC_MAXBLKSIZE);
+		WRITE64((u64) svc_max_payload(rqstp));
 	}
 	if (bmval0 & FATTR4_WORD0_MAXWRITE) {
 		if ((buflen -= 8) < 0)
 			goto out_resource;
-		WRITE64((u64) NFSSVC_MAXBLKSIZE);
+		WRITE64((u64) svc_max_payload(rqstp));
 	}
 	if (bmval1 & FATTR4_WORD1_MODE) {
 		if ((buflen -= 4) < 0)
@@ -1845,7 +2010,6 @@
 	nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
 				    resp->p, &buflen, getattr->ga_bmval,
 				    resp->rqstp);
-
 	if (!nfserr)
 		resp->p += buflen;
 	return nfserr;
@@ -2039,7 +2203,8 @@
 }
 
 static int
-nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
+nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr,
+		  struct nfsd4_read *read)
 {
 	u32 eof;
 	int v, pn;
@@ -2054,31 +2219,33 @@
 
 	RESERVE_SPACE(8); /* eof flag and byte count */
 
-	maxcount = NFSSVC_MAXBLKSIZE;
+	maxcount = svc_max_payload(resp->rqstp);
 	if (maxcount > read->rd_length)
 		maxcount = read->rd_length;
 
 	len = maxcount;
 	v = 0;
 	while (len > 0) {
-		pn = resp->rqstp->rq_resused;
-		svc_take_page(resp->rqstp);
-		read->rd_iov[v].iov_base = page_address(resp->rqstp->rq_respages[pn]);
-		read->rd_iov[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE;
+		pn = resp->rqstp->rq_resused++;
+		resp->rqstp->rq_vec[v].iov_base =
+			page_address(resp->rqstp->rq_respages[pn]);
+		resp->rqstp->rq_vec[v].iov_len =
+			len < PAGE_SIZE ? len : PAGE_SIZE;
 		v++;
 		len -= PAGE_SIZE;
 	}
 	read->rd_vlen = v;
 
 	nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
-			read->rd_offset, read->rd_iov, read->rd_vlen,
+			read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
 			&maxcount);
 
 	if (nfserr == nfserr_symlink)
 		nfserr = nfserr_inval;
 	if (nfserr)
 		return nfserr;
-	eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);
+	eof = (read->rd_offset + maxcount >=
+	       read->rd_fhp->fh_dentry->d_inode->i_size);
 
 	WRITE32(eof);
 	WRITE32(maxcount);
@@ -2088,7 +2255,6 @@
 	resp->xbuf->page_len = maxcount;
 
 	/* Use rest of head for padding and remaining ops: */
-	resp->rqstp->rq_restailpage = 0;
 	resp->xbuf->tail[0].iov_base = p;
 	resp->xbuf->tail[0].iov_len = 0;
 	if (maxcount&3) {
@@ -2113,8 +2279,7 @@
 	if (resp->xbuf->page_len)
 		return nfserr_resource;
 
-	svc_take_page(resp->rqstp);
-	page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+	page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
 
 	maxcount = PAGE_SIZE;
 	RESERVE_SPACE(4);
@@ -2138,7 +2303,6 @@
 	resp->xbuf->page_len = maxcount;
 
 	/* Use rest of head for padding and remaining ops: */
-	resp->rqstp->rq_restailpage = 0;
 	resp->xbuf->tail[0].iov_base = p;
 	resp->xbuf->tail[0].iov_len = 0;
 	if (maxcount&3) {
@@ -2189,8 +2353,7 @@
 		goto err_no_verf;
 	}
 
-	svc_take_page(resp->rqstp);
-	page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+	page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
 	readdir->common.err = 0;
 	readdir->buflen = maxcount;
 	readdir->buffer = page;
@@ -2215,10 +2378,10 @@
 	p = readdir->buffer;
 	*p++ = 0;	/* no more entries */
 	*p++ = htonl(readdir->common.err == nfserr_eof);
-	resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+	resp->xbuf->page_len = ((char*)p) - (char*)page_address(
+		resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
 
 	/* Use rest of head for padding and remaining ops: */
-	resp->rqstp->rq_restailpage = 0;
 	resp->xbuf->tail[0].iov_base = tailbase;
 	resp->xbuf->tail[0].iov_len = 0;
 	resp->p = resp->xbuf->tail[0].iov_base;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 5c6a477..39aed90 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -57,6 +57,7 @@
 	NFSD_Pool_Threads,
 	NFSD_Versions,
 	NFSD_Ports,
+	NFSD_MaxBlkSize,
 	/*
 	 * The below MUST come last.  Otherwise we leave a hole in nfsd_files[]
 	 * with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
@@ -82,6 +83,7 @@
 static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
 static ssize_t write_versions(struct file *file, char *buf, size_t size);
 static ssize_t write_ports(struct file *file, char *buf, size_t size);
+static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
 #ifdef CONFIG_NFSD_V4
 static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
 static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
@@ -100,6 +102,7 @@
 	[NFSD_Pool_Threads] = write_pool_threads,
 	[NFSD_Versions] = write_versions,
 	[NFSD_Ports] = write_ports,
+	[NFSD_MaxBlkSize] = write_maxblksize,
 #ifdef CONFIG_NFSD_V4
 	[NFSD_Leasetime] = write_leasetime,
 	[NFSD_RecoveryDir] = write_recoverydir,
@@ -523,18 +526,20 @@
 		err = nfsd_create_serv();
 		if (!err) {
 			int proto = 0;
-			err = lockd_up(proto);
-			if (!err) {
-				err = svc_addsock(nfsd_serv, fd, buf, &proto);
-				if (err)
-					lockd_down();
+			err = svc_addsock(nfsd_serv, fd, buf, &proto);
+			if (err >= 0) {
+				err = lockd_up(proto);
+				if (err < 0)
+					svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
 			}
 			/* Decrease the count, but don't shutdown the
 			 * the service
 			 */
+			lock_kernel();
 			nfsd_serv->sv_nrthreads--;
+			unlock_kernel();
 		}
-		return err;
+		return err < 0 ? err : 0;
 	}
 	if (buf[0] == '-') {
 		char *toclose = kstrdup(buf+1, GFP_KERNEL);
@@ -545,12 +550,43 @@
 		if (nfsd_serv)
 			len = svc_sock_names(buf, nfsd_serv, toclose);
 		unlock_kernel();
+		if (len >= 0)
+			lockd_down();
 		kfree(toclose);
 		return len;
 	}
 	return -EINVAL;
 }
 
+int nfsd_max_blksize;
+
+static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
+{
+	char *mesg = buf;
+	if (size > 0) {
+		int bsize;
+		int rv = get_int(&mesg, &bsize);
+		if (rv)
+			return rv;
+		/* force bsize into allowed range and
+		 * required alignment.
+		 */
+		if (bsize < 1024)
+			bsize = 1024;
+		if (bsize > NFSSVC_MAXBLKSIZE)
+			bsize = NFSSVC_MAXBLKSIZE;
+		bsize &= ~(1024-1);
+		lock_kernel();
+		if (nfsd_serv && nfsd_serv->sv_nrthreads) {
+			unlock_kernel();
+			return -EBUSY;
+		}
+		nfsd_max_blksize = bsize;
+		unlock_kernel();
+	}
+	return sprintf(buf, "%d\n", nfsd_max_blksize);
+}
+
 #ifdef CONFIG_NFSD_V4
 extern time_t nfs4_leasetime(void);
 
@@ -616,6 +652,7 @@
 		[NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
 		[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
 		[NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
+		[NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
 #ifdef CONFIG_NFSD_V4
 		[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
 		[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 06cd0db..9ee1dab 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -146,20 +146,20 @@
 	 * status, 17 words for fattr, and 1 word for the byte count.
 	 */
 
-	if (NFSSVC_MAXBLKSIZE < argp->count) {
+	if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
 		printk(KERN_NOTICE
 			"oversized read request from %u.%u.%u.%u:%d (%d bytes)\n",
 				NIPQUAD(rqstp->rq_addr.sin_addr.s_addr),
 				ntohs(rqstp->rq_addr.sin_port),
 				argp->count);
-		argp->count = NFSSVC_MAXBLKSIZE;
+		argp->count = NFSSVC_MAXBLKSIZE_V2;
 	}
 	svc_reserve(rqstp, (19<<2) + argp->count + 4);
 
 	resp->count = argp->count;
 	nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
 				  argp->offset,
-			   	  argp->vec, argp->vlen,
+			   	  rqstp->rq_vec, argp->vlen,
 				  &resp->count);
 
 	if (nfserr) return nfserr;
@@ -185,7 +185,7 @@
 
 	nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
 				   argp->offset,
-				   argp->vec, argp->vlen,
+				   rqstp->rq_vec, argp->vlen,
 				   argp->len,
 				   &stable);
 	return nfsd_return_attrs(nfserr, resp);
@@ -225,7 +225,7 @@
 	nfserr = nfserr_exist;
 	if (isdotent(argp->name, argp->len))
 		goto done;
-	fh_lock(dirfhp);
+	fh_lock_nested(dirfhp, I_MUTEX_PARENT);
 	dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
 	if (IS_ERR(dchild)) {
 		nfserr = nfserrno(PTR_ERR(dchild));
@@ -553,7 +553,7 @@
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(lookup,	 diropargs,	diropres,	fhandle,	RC_NOCACHE, ST+FH+AT),
   PROC(readlink, readlinkargs,	readlinkres,	none,		RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
-  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE/4),
+  PROC(read,	 readargs,	readres,	fhandle,	RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4),
   PROC(none,	 void,		void,		none,		RC_NOCACHE, ST),
   PROC(write,	 writeargs,	attrstat,	fhandle,	RC_REPLBUFF, ST+AT),
   PROC(create,	 createargs,	diropres,	fhandle,	RC_REPLBUFF, ST+FH+AT),
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 1944305..6fa6340 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -198,9 +198,26 @@
 		unlock_kernel();
 		return 0;
 	}
+	if (nfsd_max_blksize == 0) {
+		/* choose a suitable default */
+		struct sysinfo i;
+		si_meminfo(&i);
+		/* Aim for 1/4096 of memory per thread
+		 * This gives 1MB on 4Gig machines
+		 * But only uses 32K on 128M machines.
+		 * Bottom out at 8K on 32M and smaller.
+		 * Of course, this is only a default.
+		 */
+		nfsd_max_blksize = NFSSVC_MAXBLKSIZE;
+		i.totalram <<= PAGE_SHIFT - 12;
+		while (nfsd_max_blksize > i.totalram &&
+		       nfsd_max_blksize >= 8*1024*2)
+			nfsd_max_blksize /= 2;
+	}
 
 	atomic_set(&nfsd_busy, 0);
-	nfsd_serv = svc_create_pooled(&nfsd_program, NFSD_BUFSIZE,
+	nfsd_serv = svc_create_pooled(&nfsd_program,
+				      NFSD_BUFSIZE - NFSSVC_MAXBLKSIZE + nfsd_max_blksize,
 				      nfsd_last_thread,
 				      nfsd, SIG_NOCLEAN, THIS_MODULE);
 	if (nfsd_serv == NULL)
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index 3f14a17..1135c0d 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -254,19 +254,18 @@
 	len = args->count     = ntohl(*p++);
 	p++; /* totalcount - unused */
 
-	if (len > NFSSVC_MAXBLKSIZE)
-		len = NFSSVC_MAXBLKSIZE;
+	if (len > NFSSVC_MAXBLKSIZE_V2)
+		len = NFSSVC_MAXBLKSIZE_V2;
 
 	/* set up somewhere to store response.
 	 * We take pages, put them on reslist and include in iovec
 	 */
 	v=0;
 	while (len > 0) {
-		pn=rqstp->rq_resused;
-		svc_take_page(rqstp);
-		args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
-		args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
-		len -= args->vec[v].iov_len;
+		pn = rqstp->rq_resused++;
+		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+		rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
+		len -= rqstp->rq_vec[v].iov_len;
 		v++;
 	}
 	args->vlen = v;
@@ -286,21 +285,21 @@
 	args->offset = ntohl(*p++);	/* offset */
 	p++;				/* totalcount */
 	len = args->len = ntohl(*p++);
-	args->vec[0].iov_base = (void*)p;
-	args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
+	rqstp->rq_vec[0].iov_base = (void*)p;
+	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
 				(((void*)p) - rqstp->rq_arg.head[0].iov_base);
-	if (len > NFSSVC_MAXBLKSIZE)
-		len = NFSSVC_MAXBLKSIZE;
+	if (len > NFSSVC_MAXBLKSIZE_V2)
+		len = NFSSVC_MAXBLKSIZE_V2;
 	v = 0;
-	while (len > args->vec[v].iov_len) {
-		len -= args->vec[v].iov_len;
+	while (len > rqstp->rq_vec[v].iov_len) {
+		len -= rqstp->rq_vec[v].iov_len;
 		v++;
-		args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
-		args->vec[v].iov_len = PAGE_SIZE;
+		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
+		rqstp->rq_vec[v].iov_len = PAGE_SIZE;
 	}
-	args->vec[v].iov_len = len;
+	rqstp->rq_vec[v].iov_len = len;
 	args->vlen = v+1;
-	return args->vec[0].iov_len > 0;
+	return rqstp->rq_vec[0].iov_len > 0;
 }
 
 int
@@ -333,8 +332,7 @@
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
-	svc_take_page(rqstp);
-	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -375,8 +373,7 @@
 	if (args->count > PAGE_SIZE)
 		args->count = PAGE_SIZE;
 
-	svc_take_page(rqstp);
-	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -416,7 +413,6 @@
 	rqstp->rq_res.page_len = resp->len;
 	if (resp->len & 3) {
 		/* need to pad the tail */
-		rqstp->rq_restailpage = 0;
 		rqstp->rq_res.tail[0].iov_base = p;
 		*p = 0;
 		rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -436,7 +432,6 @@
 	rqstp->rq_res.page_len = resp->count;
 	if (resp->count & 3) {
 		/* need to pad the tail */
-		rqstp->rq_restailpage = 0;
 		rqstp->rq_res.tail[0].iov_base = p;
 		*p = 0;
 		rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
@@ -463,7 +458,7 @@
 {
 	struct kstatfs	*stat = &resp->stats;
 
-	*p++ = htonl(NFSSVC_MAXBLKSIZE);	/* max transfer size */
+	*p++ = htonl(NFSSVC_MAXBLKSIZE_V2);	/* max transfer size */
 	*p++ = htonl(stat->f_bsize);
 	*p++ = htonl(stat->f_blocks);
 	*p++ = htonl(stat->f_bfree);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 443ebc5..1141bd2 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -54,6 +54,7 @@
 #include <linux/nfsd_idmap.h>
 #include <linux/security.h>
 #endif /* CONFIG_NFSD_V4 */
+#include <linux/jhash.h>
 
 #include <asm/uaccess.h>
 
@@ -81,10 +82,19 @@
 	dev_t			p_dev;
 	int			p_set;
 	struct file_ra_state	p_ra;
+	unsigned int		p_hindex;
 };
 
+struct raparm_hbucket {
+	struct raparms		*pb_head;
+	spinlock_t		pb_lock;
+} ____cacheline_aligned_in_smp;
+
 static struct raparms *		raparml;
-static struct raparms *		raparm_cache;
+#define RAPARM_HASH_BITS	4
+#define RAPARM_HASH_SIZE	(1<<RAPARM_HASH_BITS)
+#define RAPARM_HASH_MASK	(RAPARM_HASH_SIZE-1)
+static struct raparm_hbucket	raparm_hash[RAPARM_HASH_SIZE];
 
 /* 
  * Called from nfsd_lookup and encode_dirent. Check if we have crossed 
@@ -437,13 +447,11 @@
 	} else if (error < 0)
 		goto out_nfserr;
 
-	if (pacl) {
-		error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
-		if (error < 0)
-			goto out_nfserr;
-	}
+	error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+	if (error < 0)
+		goto out_nfserr;
 
-	if (dpacl) {
+	if (S_ISDIR(inode->i_mode)) {
 		error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
 		if (error < 0)
 			goto out_nfserr;
@@ -743,16 +751,20 @@
  * Obtain the readahead parameters for the file
  * specified by (dev, ino).
  */
-static DEFINE_SPINLOCK(ra_lock);
 
 static inline struct raparms *
 nfsd_get_raparms(dev_t dev, ino_t ino)
 {
 	struct raparms	*ra, **rap, **frap = NULL;
 	int depth = 0;
+	unsigned int hash;
+	struct raparm_hbucket *rab;
 
-	spin_lock(&ra_lock);
-	for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
+	hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;
+	rab = &raparm_hash[hash];
+
+	spin_lock(&rab->pb_lock);
+	for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {
 		if (ra->p_ino == ino && ra->p_dev == dev)
 			goto found;
 		depth++;
@@ -761,7 +773,7 @@
 	}
 	depth = nfsdstats.ra_size*11/10;
 	if (!frap) {	
-		spin_unlock(&ra_lock);
+		spin_unlock(&rab->pb_lock);
 		return NULL;
 	}
 	rap = frap;
@@ -769,15 +781,16 @@
 	ra->p_dev = dev;
 	ra->p_ino = ino;
 	ra->p_set = 0;
+	ra->p_hindex = hash;
 found:
-	if (rap != &raparm_cache) {
+	if (rap != &rab->pb_head) {
 		*rap = ra->p_next;
-		ra->p_next   = raparm_cache;
-		raparm_cache = ra;
+		ra->p_next   = rab->pb_head;
+		rab->pb_head = ra;
 	}
 	ra->p_count++;
 	nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
-	spin_unlock(&ra_lock);
+	spin_unlock(&rab->pb_lock);
 	return ra;
 }
 
@@ -791,22 +804,26 @@
 {
 	unsigned long count = desc->count;
 	struct svc_rqst *rqstp = desc->arg.data;
+	struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
 
 	if (size > count)
 		size = count;
 
 	if (rqstp->rq_res.page_len == 0) {
 		get_page(page);
-		rqstp->rq_respages[rqstp->rq_resused++] = page;
+		put_page(*pp);
+		*pp = page;
+		rqstp->rq_resused++;
 		rqstp->rq_res.page_base = offset;
 		rqstp->rq_res.page_len = size;
-	} else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) {
+	} else if (page != pp[-1]) {
 		get_page(page);
-		rqstp->rq_respages[rqstp->rq_resused++] = page;
+		put_page(*pp);
+		*pp = page;
+		rqstp->rq_resused++;
 		rqstp->rq_res.page_len += size;
-	} else {
+	} else
 		rqstp->rq_res.page_len += size;
-	}
 
 	desc->count = count - size;
 	desc->written += size;
@@ -837,7 +854,7 @@
 		file->f_ra = ra->p_ra;
 
 	if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
-		svc_pushback_unused_pages(rqstp);
+		rqstp->rq_resused = 1;
 		err = file->f_op->sendfile(file, &offset, *count,
 						 nfsd_read_actor, rqstp);
 	} else {
@@ -849,11 +866,12 @@
 
 	/* Write back readahead params */
 	if (ra) {
-		spin_lock(&ra_lock);
+		struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
+		spin_lock(&rab->pb_lock);
 		ra->p_ra = file->f_ra;
 		ra->p_set = 1;
 		ra->p_count--;
-		spin_unlock(&ra_lock);
+		spin_unlock(&rab->pb_lock);
 	}
 
 	if (err >= 0) {
@@ -1829,11 +1847,11 @@
 void
 nfsd_racache_shutdown(void)
 {
-	if (!raparm_cache)
+	if (!raparml)
 		return;
 	dprintk("nfsd: freeing readahead buffers.\n");
 	kfree(raparml);
-	raparm_cache = raparml = NULL;
+	raparml = NULL;
 }
 /*
  * Initialize readahead param cache
@@ -1842,19 +1860,31 @@
 nfsd_racache_init(int cache_size)
 {
 	int	i;
+	int	j = 0;
+	int	nperbucket;
 
-	if (raparm_cache)
+
+	if (raparml)
 		return 0;
+	if (cache_size < 2*RAPARM_HASH_SIZE)
+		cache_size = 2*RAPARM_HASH_SIZE;
 	raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL);
 
 	if (raparml != NULL) {
 		dprintk("nfsd: allocating %d readahead buffers.\n",
 			cache_size);
+		for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
+			raparm_hash[i].pb_head = NULL;
+			spin_lock_init(&raparm_hash[i].pb_lock);
+		}
+		nperbucket = cache_size >> RAPARM_HASH_BITS;
 		memset(raparml, 0, sizeof(struct raparms) * cache_size);
 		for (i = 0; i < cache_size - 1; i++) {
-			raparml[i].p_next = raparml + i + 1;
+			if (i % nperbucket == 0)
+				raparm_hash[j++].pb_head = raparml + i;
+			if (i % nperbucket < nperbucket-1)
+				raparml[i].p_next = raparml + i + 1;
 		}
-		raparm_cache = raparml;
 	} else {
 		printk(KERN_WARNING
 		       "nfsd: Could not allocate memory read-ahead cache.\n");
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index c093642..b67ce935 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -2,7 +2,6 @@
  * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
  */
 
-#include <linux/config.h>
 #include <linux/time.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/reiserfs_acl.h>
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 7e5a2f5..9c69bca 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1780,7 +1780,7 @@
 		err = -EDQUOT;
 		goto out_end_trans;
 	}
-	if (!dir || !dir->i_nlink) {
+	if (!dir->i_nlink) {
 		err = -EPERM;
 		goto out_bad_inode;
 	}
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h b/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
deleted file mode 100644
index 79f851e..0000000
--- a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * USART registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91RM9200_USART_H
-#define AT91RM9200_USART_H
-
-#define AT91_US_CR		0x00			/* Control Register */
-#define		AT91_US_RSTRX		(1 <<  2)		/* Reset Receiver */
-#define		AT91_US_RSTTX		(1 <<  3)		/* Reset Transmitter */
-#define		AT91_US_RXEN		(1 <<  4)		/* Receiver Enable */
-#define		AT91_US_RXDIS		(1 <<  5)		/* Receiver Disable */
-#define		AT91_US_TXEN		(1 <<  6)		/* Transmitter Enable */
-#define		AT91_US_TXDIS		(1 <<  7)		/* Transmitter Disable */
-#define		AT91_US_RSTSTA		(1 <<  8)		/* Reset Status Bits */
-#define		AT91_US_STTBRK		(1 <<  9)		/* Start Break */
-#define		AT91_US_STPBRK		(1 << 10)		/* Stop Break */
-#define		AT91_US_STTTO		(1 << 11)		/* Start Time-out */
-#define		AT91_US_SENDA		(1 << 12)		/* Send Address */
-#define		AT91_US_RSTIT		(1 << 13)		/* Reset Iterations */
-#define		AT91_US_RSTNACK		(1 << 14)		/* Reset Non Acknowledge */
-#define		AT91_US_RETTO		(1 << 15)		/* Rearm Time-out */
-#define		AT91_US_DTREN		(1 << 16)		/* Data Terminal Ready Enable */
-#define		AT91_US_DTRDIS		(1 << 17)		/* Data Terminal Ready Disable */
-#define		AT91_US_RTSEN		(1 << 18)		/* Request To Send Enable */
-#define		AT91_US_RTSDIS		(1 << 19)		/* Request To Send Disable */
-
-#define AT91_US_MR		0x04			/* Mode Register */
-#define		AT91_US_USMODE		(0xf <<  0)		/* Mode of the USART */
-#define			AT91_US_USMODE_NORMAL		0
-#define			AT91_US_USMODE_RS485		1
-#define			AT91_US_USMODE_HWHS		2
-#define			AT91_US_USMODE_MODEM		3
-#define			AT91_US_USMODE_ISO7816_T0	4
-#define			AT91_US_USMODE_ISO7816_T1	6
-#define			AT91_US_USMODE_IRDA		8
-#define		AT91_US_USCLKS		(3   <<  4)		/* Clock Selection */
-#define		AT91_US_CHRL		(3   <<  6)		/* Character Length */
-#define			AT91_US_CHRL_5			(0 <<  6)
-#define			AT91_US_CHRL_6			(1 <<  6)
-#define			AT91_US_CHRL_7			(2 <<  6)
-#define			AT91_US_CHRL_8			(3 <<  6)
-#define		AT91_US_SYNC		(1 <<  8)		/* Synchronous Mode Select */
-#define		AT91_US_PAR		(7 <<  9)		/* Parity Type */
-#define			AT91_US_PAR_EVEN		(0 <<  9)
-#define			AT91_US_PAR_ODD			(1 <<  9)
-#define			AT91_US_PAR_SPACE		(2 <<  9)
-#define			AT91_US_PAR_MARK		(3 <<  9)
-#define			AT91_US_PAR_NONE		(4 <<  9)
-#define			AT91_US_PAR_MULTI_DROP		(6 <<  9)
-#define		AT91_US_NBSTOP		(3 << 12)		/* Number of Stop Bits */
-#define			AT91_US_NBSTOP_1		(0 << 12)
-#define			AT91_US_NBSTOP_1_5		(1 << 12)
-#define			AT91_US_NBSTOP_2		(2 << 12)
-#define		AT91_US_CHMODE		(3 << 14)		/* Channel Mode */
-#define			AT91_US_CHMODE_NORMAL		(0 << 14)
-#define			AT91_US_CHMODE_ECHO		(1 << 14)
-#define			AT91_US_CHMODE_LOC_LOOP		(2 << 14)
-#define			AT91_US_CHMODE_REM_LOOP		(3 << 14)
-#define		AT91_US_MSBF		(1 << 16)		/* Bit Order */
-#define		AT91_US_MODE9		(1 << 17)		/* 9-bit Character Length */
-#define		AT91_US_CLKO		(1 << 18)		/* Clock Output Select */
-#define		AT91_US_OVER		(1 << 19)		/* Oversampling Mode */
-#define		AT91_US_INACK		(1 << 20)		/* Inhibit Non Acknowledge */
-#define		AT91_US_DSNACK		(1 << 21)		/* Disable Successive NACK */
-#define		AT91_US_MAX_ITER	(7 << 24)		/* Max Iterations */
-#define		AT91_US_FILTER		(1 << 28)		/* Infrared Receive Line Filter */
-
-#define AT91_US_IER		0x08			/* Interrupt Enable Register */
-#define		AT91_US_RXRDY		(1 <<  0)		/* Receiver Ready */
-#define		AT91_US_TXRDY		(1 <<  1)		/* Transmitter Ready */
-#define		AT91_US_RXBRK		(1 <<  2)		/* Break Received / End of Break */
-#define		AT91_US_ENDRX		(1 <<  3)		/* End of Receiver Transfer */
-#define		AT91_US_ENDTX		(1 <<  4)		/* End of Transmitter Transfer */
-#define		AT91_US_OVRE		(1 <<  5)		/* Overrun Error */
-#define		AT91_US_FRAME		(1 <<  6)		/* Framing Error */
-#define		AT91_US_PARE		(1 <<  7)		/* Parity Error */
-#define		AT91_US_TIMEOUT		(1 <<  8)		/* Receiver Time-out */
-#define		AT91_US_TXEMPTY		(1 <<  9)		/* Transmitter Empty */
-#define		AT91_US_ITERATION	(1 << 10)		/* Max number of Repetitions Reached */
-#define		AT91_US_TXBUFE		(1 << 11)		/* Transmission Buffer Empty */
-#define		AT91_US_RXBUFF		(1 << 12)		/* Reception Buffer Full */
-#define		AT91_US_NACK		(1 << 13)		/* Non Acknowledge */
-#define		AT91_US_RIIC		(1 << 16)		/* Ring Indicator Input Change */
-#define		AT91_US_DSRIC		(1 << 17)		/* Data Set Ready Input Change */
-#define		AT91_US_DCDIC		(1 << 18)		/* Data Carrier Detect Input Change */
-#define		AT91_US_CTSIC		(1 << 19)		/* Clear to Send Input Change */
-#define		AT91_US_RI		(1 << 20)		/* RI */
-#define		AT91_US_DSR		(1 << 21)		/* DSR */
-#define		AT91_US_DCD		(1 << 22)		/* DCD */
-#define		AT91_US_CTS		(1 << 23)		/* CTS */
-
-#define AT91_US_IDR		0x0c			/* Interrupt Disable Register */
-#define AT91_US_IMR		0x10			/* Interrupt Mask Register */
-#define AT91_US_CSR		0x14			/* Channel Status Register */
-#define AT91_US_RHR		0x18			/* Receiver Holding Register */
-#define AT91_US_THR		0x1c			/* Transmitter Holding Register */
-
-#define AT91_US_BRGR		0x20			/* Baud Rate Generator Register */
-#define		AT91_US_CD		(0xffff << 0)		/* Clock Divider */
-
-#define AT91_US_RTOR		0x24			/* Receiver Time-out Register */
-#define		AT91_US_TO		(0xffff << 0)		/* Time-out Value */
-
-#define AT91_US_TTGR		0x28			/* Transmitter Timeguard Register */
-#define		AT91_US_TG		(0xff << 0)		/* Timeguard Value */
-
-#define AT91_US_FIDI		0x40			/* FI DI Ratio Register */
-#define AT91_US_NER		0x44			/* Number of Errors Register */
-#define AT91_US_IF		0x4c			/* IrDA Filter Register */
-
-#endif
diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h
index c1ca9a4..3cc9aec 100644
--- a/include/asm-arm/arch-at91rm9200/board.h
+++ b/include/asm-arm/arch-at91rm9200/board.h
@@ -97,12 +97,13 @@
 	unsigned short	nr_tty;		/* number of serial tty's */
 	short		tty_map[];	/* map UART to tty number */
 };
-extern struct platform_device *at91_default_console_device;
+extern struct platform_device *atmel_default_console_device;
 extern void __init at91_init_serial(struct at91_uart_config *config);
 
-struct at91_uart_data {
+struct atmel_uart_data {
 	short		use_dma_tx;	/* use transmit DMA? */
 	short		use_dma_rx;	/* use receive DMA? */
+	void __iomem	*regs;		/* virtual base address, if any */
 };
 extern void __init at91_add_device_serial(void);
 
diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91rm9200/hardware.h
index 6551b4d..9ca4cc9 100644
--- a/include/asm-arm/arch-at91rm9200/hardware.h
+++ b/include/asm-arm/arch-at91rm9200/hardware.h
@@ -44,7 +44,7 @@
 #define AT91_SRAM_VIRT_BASE	(AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE)
 
 /* Serial ports */
-#define AT91_NR_UART		5		/* 4 USART3's and one DBGU port */
+#define ATMEL_MAX_UART		5		/* 4 USART3's and one DBGU port */
 
 /* FLASH */
 #define AT91_FLASH_BASE		0x10000000	/* NCS0: Flash physical base address */
diff --git a/include/asm-arm/arch-lh7a40x/clocks.h b/include/asm-arm/arch-lh7a40x/clocks.h
index bee02fd..7d0ba18 100644
--- a/include/asm-arm/arch-lh7a40x/clocks.h
+++ b/include/asm-arm/arch-lh7a40x/clocks.h
@@ -8,8 +8,6 @@
  *
  */
 
-#include <linux/config.h>
-
 #ifndef __ASM_ARCH_CLOCKS_H
 #define __ASM_ARCH_CLOCKS_H
 
diff --git a/include/asm-arm/mach/serial_at91.h b/include/asm-arm/mach/serial_at91.h
index 1290bb3..55b317a 100644
--- a/include/asm-arm/mach/serial_at91.h
+++ b/include/asm-arm/mach/serial_at91.h
@@ -14,7 +14,7 @@
  * This is a temporary structure for registering these
  * functions; it is intended to be discarded after boot.
  */
-struct at91_port_fns {
+struct atmel_port_fns {
 	void	(*set_mctrl)(struct uart_port *, u_int);
 	u_int	(*get_mctrl)(struct uart_port *);
 	void	(*enable_ms)(struct uart_port *);
@@ -24,10 +24,10 @@
 	void	(*close)(struct uart_port *);
 };
 
-#if defined(CONFIG_SERIAL_AT91)
-void at91_register_uart_fns(struct at91_port_fns *fns);
+#if defined(CONFIG_SERIAL_ATMEL)
+void atmel_register_uart_fns(struct atmel_port_fns *fns);
 #else
-#define at91_register_uart_fns(fns) do { } while (0)
+#define atmel_register_uart_fns(fns) do { } while (0)
 #endif
 
 
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
index b13322d..c1b264d 100644
--- a/include/asm-arm/pgtable-nommu.h
+++ b/include/asm-arm/pgtable-nommu.h
@@ -13,7 +13,6 @@
 
 #ifndef __ASSEMBLY__
 
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <asm/processor.h>
 #include <asm/page.h>
diff --git a/include/asm-avr32/arch-at32ap/at91rm9200_usart.h b/include/asm-avr32/arch-at32ap/at91rm9200_usart.h
deleted file mode 100644
index 79f851e..0000000
--- a/include/asm-avr32/arch-at32ap/at91rm9200_usart.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * USART registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91RM9200_USART_H
-#define AT91RM9200_USART_H
-
-#define AT91_US_CR		0x00			/* Control Register */
-#define		AT91_US_RSTRX		(1 <<  2)		/* Reset Receiver */
-#define		AT91_US_RSTTX		(1 <<  3)		/* Reset Transmitter */
-#define		AT91_US_RXEN		(1 <<  4)		/* Receiver Enable */
-#define		AT91_US_RXDIS		(1 <<  5)		/* Receiver Disable */
-#define		AT91_US_TXEN		(1 <<  6)		/* Transmitter Enable */
-#define		AT91_US_TXDIS		(1 <<  7)		/* Transmitter Disable */
-#define		AT91_US_RSTSTA		(1 <<  8)		/* Reset Status Bits */
-#define		AT91_US_STTBRK		(1 <<  9)		/* Start Break */
-#define		AT91_US_STPBRK		(1 << 10)		/* Stop Break */
-#define		AT91_US_STTTO		(1 << 11)		/* Start Time-out */
-#define		AT91_US_SENDA		(1 << 12)		/* Send Address */
-#define		AT91_US_RSTIT		(1 << 13)		/* Reset Iterations */
-#define		AT91_US_RSTNACK		(1 << 14)		/* Reset Non Acknowledge */
-#define		AT91_US_RETTO		(1 << 15)		/* Rearm Time-out */
-#define		AT91_US_DTREN		(1 << 16)		/* Data Terminal Ready Enable */
-#define		AT91_US_DTRDIS		(1 << 17)		/* Data Terminal Ready Disable */
-#define		AT91_US_RTSEN		(1 << 18)		/* Request To Send Enable */
-#define		AT91_US_RTSDIS		(1 << 19)		/* Request To Send Disable */
-
-#define AT91_US_MR		0x04			/* Mode Register */
-#define		AT91_US_USMODE		(0xf <<  0)		/* Mode of the USART */
-#define			AT91_US_USMODE_NORMAL		0
-#define			AT91_US_USMODE_RS485		1
-#define			AT91_US_USMODE_HWHS		2
-#define			AT91_US_USMODE_MODEM		3
-#define			AT91_US_USMODE_ISO7816_T0	4
-#define			AT91_US_USMODE_ISO7816_T1	6
-#define			AT91_US_USMODE_IRDA		8
-#define		AT91_US_USCLKS		(3   <<  4)		/* Clock Selection */
-#define		AT91_US_CHRL		(3   <<  6)		/* Character Length */
-#define			AT91_US_CHRL_5			(0 <<  6)
-#define			AT91_US_CHRL_6			(1 <<  6)
-#define			AT91_US_CHRL_7			(2 <<  6)
-#define			AT91_US_CHRL_8			(3 <<  6)
-#define		AT91_US_SYNC		(1 <<  8)		/* Synchronous Mode Select */
-#define		AT91_US_PAR		(7 <<  9)		/* Parity Type */
-#define			AT91_US_PAR_EVEN		(0 <<  9)
-#define			AT91_US_PAR_ODD			(1 <<  9)
-#define			AT91_US_PAR_SPACE		(2 <<  9)
-#define			AT91_US_PAR_MARK		(3 <<  9)
-#define			AT91_US_PAR_NONE		(4 <<  9)
-#define			AT91_US_PAR_MULTI_DROP		(6 <<  9)
-#define		AT91_US_NBSTOP		(3 << 12)		/* Number of Stop Bits */
-#define			AT91_US_NBSTOP_1		(0 << 12)
-#define			AT91_US_NBSTOP_1_5		(1 << 12)
-#define			AT91_US_NBSTOP_2		(2 << 12)
-#define		AT91_US_CHMODE		(3 << 14)		/* Channel Mode */
-#define			AT91_US_CHMODE_NORMAL		(0 << 14)
-#define			AT91_US_CHMODE_ECHO		(1 << 14)
-#define			AT91_US_CHMODE_LOC_LOOP		(2 << 14)
-#define			AT91_US_CHMODE_REM_LOOP		(3 << 14)
-#define		AT91_US_MSBF		(1 << 16)		/* Bit Order */
-#define		AT91_US_MODE9		(1 << 17)		/* 9-bit Character Length */
-#define		AT91_US_CLKO		(1 << 18)		/* Clock Output Select */
-#define		AT91_US_OVER		(1 << 19)		/* Oversampling Mode */
-#define		AT91_US_INACK		(1 << 20)		/* Inhibit Non Acknowledge */
-#define		AT91_US_DSNACK		(1 << 21)		/* Disable Successive NACK */
-#define		AT91_US_MAX_ITER	(7 << 24)		/* Max Iterations */
-#define		AT91_US_FILTER		(1 << 28)		/* Infrared Receive Line Filter */
-
-#define AT91_US_IER		0x08			/* Interrupt Enable Register */
-#define		AT91_US_RXRDY		(1 <<  0)		/* Receiver Ready */
-#define		AT91_US_TXRDY		(1 <<  1)		/* Transmitter Ready */
-#define		AT91_US_RXBRK		(1 <<  2)		/* Break Received / End of Break */
-#define		AT91_US_ENDRX		(1 <<  3)		/* End of Receiver Transfer */
-#define		AT91_US_ENDTX		(1 <<  4)		/* End of Transmitter Transfer */
-#define		AT91_US_OVRE		(1 <<  5)		/* Overrun Error */
-#define		AT91_US_FRAME		(1 <<  6)		/* Framing Error */
-#define		AT91_US_PARE		(1 <<  7)		/* Parity Error */
-#define		AT91_US_TIMEOUT		(1 <<  8)		/* Receiver Time-out */
-#define		AT91_US_TXEMPTY		(1 <<  9)		/* Transmitter Empty */
-#define		AT91_US_ITERATION	(1 << 10)		/* Max number of Repetitions Reached */
-#define		AT91_US_TXBUFE		(1 << 11)		/* Transmission Buffer Empty */
-#define		AT91_US_RXBUFF		(1 << 12)		/* Reception Buffer Full */
-#define		AT91_US_NACK		(1 << 13)		/* Non Acknowledge */
-#define		AT91_US_RIIC		(1 << 16)		/* Ring Indicator Input Change */
-#define		AT91_US_DSRIC		(1 << 17)		/* Data Set Ready Input Change */
-#define		AT91_US_DCDIC		(1 << 18)		/* Data Carrier Detect Input Change */
-#define		AT91_US_CTSIC		(1 << 19)		/* Clear to Send Input Change */
-#define		AT91_US_RI		(1 << 20)		/* RI */
-#define		AT91_US_DSR		(1 << 21)		/* DSR */
-#define		AT91_US_DCD		(1 << 22)		/* DCD */
-#define		AT91_US_CTS		(1 << 23)		/* CTS */
-
-#define AT91_US_IDR		0x0c			/* Interrupt Disable Register */
-#define AT91_US_IMR		0x10			/* Interrupt Mask Register */
-#define AT91_US_CSR		0x14			/* Channel Status Register */
-#define AT91_US_RHR		0x18			/* Receiver Holding Register */
-#define AT91_US_THR		0x1c			/* Transmitter Holding Register */
-
-#define AT91_US_BRGR		0x20			/* Baud Rate Generator Register */
-#define		AT91_US_CD		(0xffff << 0)		/* Clock Divider */
-
-#define AT91_US_RTOR		0x24			/* Receiver Time-out Register */
-#define		AT91_US_TO		(0xffff << 0)		/* Time-out Value */
-
-#define AT91_US_TTGR		0x28			/* Transmitter Timeguard Register */
-#define		AT91_US_TG		(0xff << 0)		/* Timeguard Value */
-
-#define AT91_US_FIDI		0x40			/* FI DI Ratio Register */
-#define AT91_US_NER		0x44			/* Number of Errors Register */
-#define AT91_US_IF		0x4c			/* IrDA Filter Register */
-
-#endif
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index 39368e1..a39b3e9 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -9,9 +9,15 @@
 /* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
 void at32_add_system_devices(void);
 
-#define AT91_NR_UART	4
-extern struct platform_device *at91_default_console_device;
+#define ATMEL_MAX_UART	4
+extern struct platform_device *atmel_default_console_device;
 
+struct atmel_uart_data {
+	short		use_dma_tx;	/* use transmit DMA? */
+	short		use_dma_rx;	/* use receive DMA? */
+	void __iomem	*regs;		/* virtual base address, if any */
+};
+void at32_map_usart(unsigned int hw_id, unsigned int line);
 struct platform_device *at32_add_device_usart(unsigned int id);
 
 struct eth_platform_data {
diff --git a/include/asm-avr32/arch-at32ap/init.h b/include/asm-avr32/arch-at32ap/init.h
index 4372263..5e75d85 100644
--- a/include/asm-avr32/arch-at32ap/init.h
+++ b/include/asm-avr32/arch-at32ap/init.h
@@ -11,6 +11,7 @@
 #define __ASM_AVR32_AT32AP_INIT_H__
 
 void setup_platform(void);
+void setup_board(void);
 
 /* Called by setup_platform */
 void at32_clock_init(void);
diff --git a/include/asm-avr32/mach/serial_at91.h b/include/asm-avr32/mach/serial_at91.h
index 1290bb3..55b317a 100644
--- a/include/asm-avr32/mach/serial_at91.h
+++ b/include/asm-avr32/mach/serial_at91.h
@@ -14,7 +14,7 @@
  * This is a temporary structure for registering these
  * functions; it is intended to be discarded after boot.
  */
-struct at91_port_fns {
+struct atmel_port_fns {
 	void	(*set_mctrl)(struct uart_port *, u_int);
 	u_int	(*get_mctrl)(struct uart_port *);
 	void	(*enable_ms)(struct uart_port *);
@@ -24,10 +24,10 @@
 	void	(*close)(struct uart_port *);
 };
 
-#if defined(CONFIG_SERIAL_AT91)
-void at91_register_uart_fns(struct at91_port_fns *fns);
+#if defined(CONFIG_SERIAL_ATMEL)
+void atmel_register_uart_fns(struct atmel_port_fns *fns);
 #else
-#define at91_register_uart_fns(fns) do { } while (0)
+#define atmel_register_uart_fns(fns) do { } while (0)
 #endif
 
 
diff --git a/include/asm-i386/alternative-asm.i b/include/asm-i386/alternative-asm.i
index 6c47e3b..f051020 100644
--- a/include/asm-i386/alternative-asm.i
+++ b/include/asm-i386/alternative-asm.i
@@ -1,5 +1,3 @@
-#include <linux/config.h>
-
 #ifdef CONFIG_SMP
 	.macro LOCK_PREFIX
 1:	lock
diff --git a/include/asm-i386/frame.i b/include/asm-i386/frame.i
index 4d68ddc..0362025 100644
--- a/include/asm-i386/frame.i
+++ b/include/asm-i386/frame.i
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <asm/dwarf2.h>
 
 /* The annotation hides the frame from the unwinder and makes it look
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index 87e5a35..88f02a0 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -17,8 +17,6 @@
 #include <asm/irq.h>
 #include <asm/sections.h>
 
-struct hw_interrupt_type;
-
 #define NMI_VECTOR		0x02
 
 /*
@@ -30,7 +28,6 @@
 
 extern u8 irq_vector[NR_IRQ_VECTORS];
 #define IO_APIC_VECTOR(irq)	(irq_vector[irq])
-#define AUTO_ASSIGN		-1
 
 extern void (*interrupt[NR_IRQS])(void);
 
diff --git a/include/asm-i386/hypertransport.h b/include/asm-i386/hypertransport.h
new file mode 100644
index 0000000..c16c6ff
--- /dev/null
+++ b/include/asm-i386/hypertransport.h
@@ -0,0 +1,42 @@
+#ifndef ASM_HYPERTRANSPORT_H
+#define ASM_HYPERTRANSPORT_H
+
+/*
+ * Constants for x86 Hypertransport Interrupts.
+ */
+
+#define HT_IRQ_LOW_BASE			0xf8000000
+
+#define HT_IRQ_LOW_VECTOR_SHIFT		16
+#define  HT_IRQ_LOW_VECTOR_MASK		0x00ff0000
+#define  HT_IRQ_LOW_VECTOR(v)		(((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
+
+#define HT_IRQ_LOW_DEST_ID_SHIFT	8
+#define  HT_IRQ_LOW_DEST_ID_MASK	0x0000ff00
+#define  HT_IRQ_LOW_DEST_ID(v)		(((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
+
+#define HT_IRQ_LOW_DM_PHYSICAL		0x0000000
+#define HT_IRQ_LOW_DM_LOGICAL		0x0000040
+
+#define HT_IRQ_LOW_RQEOI_EDGE		0x0000000
+#define HT_IRQ_LOW_RQEOI_LEVEL		0x0000020
+
+
+#define HT_IRQ_LOW_MT_FIXED		0x0000000
+#define HT_IRQ_LOW_MT_ARBITRATED	0x0000004
+#define HT_IRQ_LOW_MT_SMI		0x0000008
+#define HT_IRQ_LOW_MT_NMI		0x000000c
+#define HT_IRQ_LOW_MT_INIT		0x0000010
+#define HT_IRQ_LOW_MT_STARTUP		0x0000014
+#define HT_IRQ_LOW_MT_EXTINT		0x0000018
+#define HT_IRQ_LOW_MT_LINT1		0x000008c
+#define HT_IRQ_LOW_MT_LINT0		0x0000098
+
+#define HT_IRQ_LOW_IRQ_MASKED		0x0000001
+
+
+#define HT_IRQ_HIGH_DEST_ID_SHIFT	0
+#define  HT_IRQ_HIGH_DEST_ID_MASK	0x00ffffff
+#define  HT_IRQ_HIGH_DEST_ID(v)		((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
+
+#endif /* ASM_HYPERTRANSPORT_H */
diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h
index 5d30927..276ea7e 100644
--- a/include/asm-i386/io_apic.h
+++ b/include/asm-i386/io_apic.h
@@ -12,46 +12,6 @@
 
 #ifdef CONFIG_X86_IO_APIC
 
-#ifdef CONFIG_PCI_MSI
-static inline int use_pci_vector(void)	{return 1;}
-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
-static inline void end_edge_ioapic_vector (unsigned int vector) { }
-#define startup_level_ioapic	startup_level_ioapic_vector
-#define shutdown_level_ioapic	mask_IO_APIC_vector
-#define enable_level_ioapic	unmask_IO_APIC_vector
-#define disable_level_ioapic	mask_IO_APIC_vector
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
-#define end_level_ioapic	end_level_ioapic_vector
-#define set_ioapic_affinity	set_ioapic_affinity_vector
-
-#define startup_edge_ioapic 	startup_edge_ioapic_vector
-#define shutdown_edge_ioapic 	disable_edge_ioapic_vector
-#define enable_edge_ioapic 	unmask_IO_APIC_vector
-#define disable_edge_ioapic 	disable_edge_ioapic_vector
-#define ack_edge_ioapic 	ack_edge_ioapic_vector
-#define end_edge_ioapic 	end_edge_ioapic_vector
-#else
-static inline int use_pci_vector(void)	{return 0;}
-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
-static inline void end_edge_ioapic_irq (unsigned int irq) { }
-#define startup_level_ioapic	startup_level_ioapic_irq
-#define shutdown_level_ioapic	mask_IO_APIC_irq
-#define enable_level_ioapic	unmask_IO_APIC_irq
-#define disable_level_ioapic	mask_IO_APIC_irq
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
-#define end_level_ioapic	end_level_ioapic_irq
-#define set_ioapic_affinity	set_ioapic_affinity_irq
-
-#define startup_edge_ioapic 	startup_edge_ioapic_irq
-#define shutdown_edge_ioapic 	disable_edge_ioapic_irq
-#define enable_edge_ioapic 	unmask_IO_APIC_irq
-#define disable_edge_ioapic 	disable_edge_ioapic_irq
-#define ack_edge_ioapic 	ack_edge_ioapic_irq
-#define end_edge_ioapic 	end_edge_ioapic_irq
-#endif
-
 #define IO_APIC_BASE(idx) \
 		((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \
 		+ (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK)))
@@ -219,6 +179,4 @@
 static inline void disable_ioapic_setup(void) { }
 #endif
 
-extern int assign_irq_vector(int irq);
-
 #endif
diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h
index b330026..7f161e7 100644
--- a/include/asm-i386/mach-default/irq_vectors_limits.h
+++ b/include/asm-i386/mach-default/irq_vectors_limits.h
@@ -1,10 +1,6 @@
 #ifndef _ASM_IRQ_VECTORS_LIMITS_H
 #define _ASM_IRQ_VECTORS_LIMITS_H
 
-#ifdef CONFIG_PCI_MSI
-#define NR_IRQS FIRST_SYSTEM_VECTOR
-#define NR_IRQ_VECTORS NR_IRQS
-#else
 #ifdef CONFIG_X86_IO_APIC
 #define NR_IRQS 224
 # if (224 >= 32 * NR_CPUS)
@@ -16,6 +12,5 @@
 #define NR_IRQS 16
 #define NR_IRQ_VECTORS NR_IRQS
 #endif
-#endif
 
 #endif /* _ASM_IRQ_VECTORS_LIMITS_H */
diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h
deleted file mode 100644
index b11c4b7..0000000
--- a/include/asm-i386/msi.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <mach_apic.h>
-
-#define LAST_DEVICE_VECTOR	(FIRST_SYSTEM_VECTOR - 1)
-#define MSI_TARGET_CPU_SHIFT	12
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
-	msi_register(&msi_apic_ops);
-	return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-i386/msidef.h b/include/asm-i386/msidef.h
new file mode 100644
index 0000000..5b8acdd
--- /dev/null
+++ b/include/asm-i386/msidef.h
@@ -0,0 +1,47 @@
+#ifndef ASM_MSIDEF_H
+#define ASM_MSIDEF_H
+
+/*
+ * Constants for Intel APIC based MSI messages.
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define  MSI_DATA_VECTOR_MASK		0x000000ff
+#define	 MSI_DATA_VECTOR(v)		(((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT	8
+#define  MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_MODE_SHIFT)
+#define  MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_MODE_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define	 MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define	 MSI_DATA_LEVEL_ASSERT		(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define  MSI_DATA_TRIGGER_EDGE		(0 << MSI_DATA_TRIGGER_SHIFT)
+#define  MSI_DATA_TRIGGER_LEVEL		(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_BASE_HI		0
+#define MSI_ADDR_BASE_LO		0xfee00000
+
+#define MSI_ADDR_DEST_MODE_SHIFT	2
+#define  MSI_ADDR_DEST_MODE_PHYSICAL	(0 << MSI_ADDR_DEST_MODE_SHIFT)
+#define	 MSI_ADDR_DEST_MODE_LOGICAL	(1 << MSI_ADDR_DEST_MODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define  MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
+#define  MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
+
+#define MSI_ADDR_DEST_ID_SHIFT		12
+#define	 MSI_ADDR_DEST_ID_MASK		0x00ffff0
+#define  MSI_ADDR_DEST_ID(dest)		(((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
+
+#endif /* ASM_MSIDEF_H */
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index 15b545a..90cba96 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -20,6 +20,7 @@
 struct mm_struct;
 struct pci_bus;
 struct task_struct;
+struct pci_dev;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
@@ -75,7 +76,9 @@
 typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
-typedef int ia64_mv_msi_init_t (void);
+
+typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
 
 static inline void
 machvec_noop (void)
@@ -154,7 +157,8 @@
 #  define platform_readl_relaxed        ia64_mv.readl_relaxed
 #  define platform_readq_relaxed        ia64_mv.readq_relaxed
 #  define platform_migrate		ia64_mv.migrate
-#  define platform_msi_init		ia64_mv.msi_init
+#  define platform_setup_msi_irq	ia64_mv.setup_msi_irq
+#  define platform_teardown_msi_irq	ia64_mv.teardown_msi_irq
 # endif
 
 /* __attribute__((__aligned__(16))) is required to make size of the
@@ -204,7 +208,8 @@
 	ia64_mv_readl_relaxed_t *readl_relaxed;
 	ia64_mv_readq_relaxed_t *readq_relaxed;
 	ia64_mv_migrate_t *migrate;
-	ia64_mv_msi_init_t *msi_init;
+	ia64_mv_setup_msi_irq_t *setup_msi_irq;
+	ia64_mv_teardown_msi_irq_t *teardown_msi_irq;
 } __attribute__((__aligned__(16))); /* align attrib? see above comment */
 
 #define MACHVEC_INIT(name)			\
@@ -250,7 +255,8 @@
 	platform_readl_relaxed,			\
 	platform_readq_relaxed,			\
 	platform_migrate,			\
-	platform_msi_init,			\
+	platform_setup_msi_irq,			\
+	platform_teardown_msi_irq,		\
 }
 
 extern struct ia64_machine_vector ia64_mv;
@@ -404,8 +410,11 @@
 #ifndef platform_migrate
 # define platform_migrate machvec_noop_task
 #endif
-#ifndef platform_msi_init
-# define platform_msi_init	((ia64_mv_msi_init_t*)NULL)
+#ifndef platform_setup_msi_irq
+# define platform_setup_msi_irq		((ia64_mv_setup_msi_irq_t*)NULL)
+#endif
+#ifndef platform_teardown_msi_irq
+# define platform_teardown_msi_irq	((ia64_mv_teardown_msi_irq_t*)NULL)
 #endif
 
 #endif /* _ASM_IA64_MACHVEC_H */
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
index cf724dc..c54b165 100644
--- a/include/asm-ia64/machvec_sn2.h
+++ b/include/asm-ia64/machvec_sn2.h
@@ -67,7 +67,8 @@
 extern ia64_mv_dma_mapping_error	sn_dma_mapping_error;
 extern ia64_mv_dma_supported		sn_dma_supported;
 extern ia64_mv_migrate_t		sn_migrate;
-extern ia64_mv_msi_init_t		sn_msi_init;
+extern ia64_mv_setup_msi_irq_t		sn_setup_msi_irq;
+extern ia64_mv_teardown_msi_irq_t	sn_teardown_msi_irq;
 
 
 /*
@@ -120,9 +121,11 @@
 #define platform_dma_supported		sn_dma_supported
 #define platform_migrate		sn_migrate
 #ifdef CONFIG_PCI_MSI
-#define platform_msi_init		sn_msi_init
+#define platform_setup_msi_irq		sn_setup_msi_irq
+#define platform_teardown_msi_irq	sn_teardown_msi_irq
 #else
-#define platform_msi_init		((ia64_mv_msi_init_t*)NULL)
+#define platform_setup_msi_irq		((ia64_mv_setup_msi_irq_t*)NULL)
+#define platform_teardown_msi_irq	((ia64_mv_teardown_msi_irq_t*)NULL)
 #endif
 
 #include <asm/sn/io.h>
diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h
deleted file mode 100644
index bb92b0d..0000000
--- a/include/asm-ia64/msi.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#define NR_VECTORS		NR_IRQS
-#define FIRST_DEVICE_VECTOR 	IA64_FIRST_DEVICE_VECTOR
-#define LAST_DEVICE_VECTOR	IA64_LAST_DEVICE_VECTOR
-static inline void set_intr_gate (int nr, void *func) {}
-#define IO_APIC_VECTOR(irq)	(irq)
-#define ack_APIC_irq		ia64_eoi
-#define MSI_TARGET_CPU_SHIFT	4
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
-	if (platform_msi_init)
-		return platform_msi_init();
-
-	/* default ops for most ia64 platforms */
-	msi_register(&msi_apic_ops);
-	return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-parisc/agp.h b/include/asm-parisc/agp.h
new file mode 100644
index 0000000..9f61d4e
--- /dev/null
+++ b/include/asm-parisc/agp.h
@@ -0,0 +1,25 @@
+#ifndef _ASM_PARISC_AGP_H
+#define _ASM_PARISC_AGP_H
+
+/*
+ * PARISC specific AGP definitions.
+ * Copyright (c) 2006 Kyle McMartin <kyle@parisc-linux.org>
+ *
+ */
+
+#define map_page_into_agp(page)		/* nothing */
+#define unmap_page_from_agp(page)	/* nothing */
+#define flush_agp_mappings()		/* nothing */
+#define flush_agp_cache()		mb()
+
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order)		\
+	((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order)	\
+	free_pages((unsigned long)(table), (order))
+
+#endif /* _ASM_PARISC_AGP_H */
diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
index 1a7bfe6..5a1e0e8 100644
--- a/include/asm-parisc/assembly.h
+++ b/include/asm-parisc/assembly.h
@@ -29,7 +29,8 @@
 #define LDREGX  ldd,s
 #define LDREGM	ldd,mb
 #define STREGM	std,ma
-#define SHRREG  shrd
+#define SHRREG	shrd
+#define SHLREG	shld
 #define RP_OFFSET	16
 #define FRAME_SIZE	128
 #define CALLEE_REG_FRAME_SIZE	144
@@ -39,7 +40,8 @@
 #define LDREGX  ldwx,s
 #define LDREGM	ldwm
 #define STREGM	stwm
-#define SHRREG  shr
+#define SHRREG	shr
+#define SHLREG	shlw
 #define RP_OFFSET	20
 #define FRAME_SIZE	64
 #define CALLEE_REG_FRAME_SIZE	128
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
index 0b459cd..2bc41f2 100644
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -191,16 +191,38 @@
 }
 #define ARCH_HAS_FLUSH_ANON_PAGE
 
-static inline void
-flush_kernel_dcache_page(struct page *page)
-{
-	flush_kernel_dcache_page_asm(page_address(page));
-}
 #define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+void flush_kernel_dcache_page_addr(void *addr);
+static inline void flush_kernel_dcache_page(struct page *page)
+{
+	flush_kernel_dcache_page_addr(page_address(page));
+}
 
 #ifdef CONFIG_DEBUG_RODATA
 void mark_rodata_ro(void);
 #endif
 
+#ifdef CONFIG_PA8X00
+/* Only pa8800, pa8900 needs this */
+#define ARCH_HAS_KMAP
+
+void kunmap_parisc(void *addr);
+
+static inline void *kmap(struct page *page)
+{
+	might_sleep();
+	return page_address(page);
+}
+
+#define kunmap(page)			kunmap_parisc(page_address(page))
+
+#define kmap_atomic(page, idx)		page_address(page)
+
+#define kunmap_atomic(addr, idx)	kunmap_parisc(addr)
+
+#define kmap_atomic_pfn(pfn, idx)	page_address(pfn_to_page(pfn))
+#define kmap_atomic_to_page(ptr)	virt_to_page(ptr)
+#endif
+
 #endif /* _PARISC_CACHEFLUSH_H */
 
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 71b4eee..fe85790 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -5,7 +5,7 @@
  */
 #include <linux/types.h>
 #include <linux/sched.h>
-#include <linux/personality.h>
+#include <linux/thread_info.h>
 
 #define COMPAT_USER_HZ 100
 
@@ -152,7 +152,7 @@
 
 static inline int __is_compat_task(struct task_struct *t)
 {
-	return personality(t->personality) == PER_LINUX32;
+	return test_ti_thread_flag(t->thread_info, TIF_32BIT);
 }
 
 static inline int is_compat_task(void)
diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h
index 9979c3c..da2cf37 100644
--- a/include/asm-parisc/dma.h
+++ b/include/asm-parisc/dma.h
@@ -72,18 +72,13 @@
 #define DMA2_MASK_ALL_REG       0xDE    /* all-channels mask (w) */
 #define DMA2_EXT_MODE_REG	(0x400 | DMA2_MODE_REG)
 
-extern spinlock_t dma_spin_lock;
-
 static __inline__ unsigned long claim_dma_lock(void)
 {
-	unsigned long flags;
-	spin_lock_irqsave(&dma_spin_lock, flags);
-	return flags;
+	return 0;
 }
 
 static __inline__ void release_dma_lock(unsigned long flags)
 {
-	spin_unlock_irqrestore(&dma_spin_lock, flags);
 }
 
 
diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h
index 6a332a9..d84bbb2 100644
--- a/include/asm-parisc/futex.h
+++ b/include/asm-parisc/futex.h
@@ -1,6 +1,71 @@
-#ifndef _ASM_FUTEX_H
-#define _ASM_FUTEX_H
+#ifndef _ASM_PARISC_FUTEX_H
+#define _ASM_PARISC_FUTEX_H
 
-#include <asm-generic/futex.h>
+#ifdef __KERNEL__
 
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+	int op = (encoded_op >> 28) & 7;
+	int cmp = (encoded_op >> 24) & 15;
+	int oparg = (encoded_op << 8) >> 20;
+	int cmparg = (encoded_op << 20) >> 20;
+	int oldval = 0, ret;
+	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+		oparg = 1 << oparg;
+
+	if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+		return -EFAULT;
+
+	inc_preempt_count();
+
+	switch (op) {
+	case FUTEX_OP_SET:
+	case FUTEX_OP_ADD:
+	case FUTEX_OP_OR:
+	case FUTEX_OP_ANDN:
+	case FUTEX_OP_XOR:
+	default:
+		ret = -ENOSYS;
+	}
+
+	dec_preempt_count();
+
+	if (!ret) {
+		switch (cmp) {
+		case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+		case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+		case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+		case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+		case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+		case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+		default: ret = -ENOSYS;
+		}
+	}
+	return ret;
+}
+
+/* Non-atomic version */
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	int err = 0;
+	int uval;
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+		return -EFAULT;
+
+	err = get_user(uval, uaddr);
+	if (err) return -EFAULT;
+	if (uval == oldval)
+		err = put_user(newval, uaddr);
+	if (err) return -EFAULT;
+	return uval;
+}
+
+#endif
 #endif
diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
index b9eb245..c1963ce 100644
--- a/include/asm-parisc/io.h
+++ b/include/asm-parisc/io.h
@@ -134,7 +134,7 @@
 }
 #define ioremap_nocache(off, sz)	ioremap((off), (sz))
 
-extern void iounmap(void __iomem *addr);
+extern void iounmap(const volatile void __iomem *addr);
 
 static inline unsigned char __raw_readb(const volatile void __iomem *addr)
 {
diff --git a/include/asm-parisc/iosapic.h b/include/asm-parisc/iosapic.h
deleted file mode 100644
index 613390e..0000000
--- a/include/asm-parisc/iosapic.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-** This file is private to iosapic driver.
-** If stuff needs to be used by another driver, move it to a common file.
-**
-** WARNING: fields most data structures here are ordered to make sure
-**          they pack nicely for 64-bit compilation. (ie sizeof(long) == 8)
-*/
-
-
-/*
-** I/O SAPIC init function
-** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
-** Call setup as part of per instance initialization.
-** (ie *not* init_module() function unless only one is present.)
-** fixup_irq is to initialize PCI IRQ line support and
-** virtualize pcidev->irq value. To be called by pci_fixup_bus().
-*/
-extern void *iosapic_register(unsigned long hpa);
-extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
-
-
-#ifdef __IA64__
-/*
-** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter.
-**     and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field.
-**
-** IA64: PIB is handled by "Local SAPIC" (integrated in the processor).
-*/
-struct local_sapic_info {
-	struct local_sapic_info *lsi_next;      /* point to next CPU info */
-	int                     *lsi_cpu_id;    /* point to logical CPU id */
-	unsigned long           *lsi_id_eid;    /* point to IA-64 CPU id */
-	int                     *lsi_status;    /* point to CPU status   */
-	void                    *lsi_private;   /* point to special info */
-};
-
-/*
-** "root" data structure which ties everything together.
-** Should always be able to start with sapic_root and locate
-** the desired information.
-*/
-struct sapic_info {
-	struct sapic_info	*si_next;	/* info is per cell */
-	int                     si_cellid;      /* cell id */
-	unsigned int            si_status;       /* status  */
-	char                    *si_pib_base;   /* intr blk base address */
-	local_sapic_info_t      *si_local_info;
-	io_sapic_info_t         *si_io_info;
-	extint_info_t           *si_extint_info;/* External Intr info      */
-};
-
-#endif /* IA64 */
-
diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
index 5cae260..399c819 100644
--- a/include/asm-parisc/irq.h
+++ b/include/asm-parisc/irq.h
@@ -31,7 +31,7 @@
 	return (irq == 2) ? 9 : irq;
 }
 
-struct hw_interrupt_type;
+struct irq_chip;
 
 /*
  * Some useful "we don't have to do anything here" handlers.  Should
@@ -39,6 +39,8 @@
  */
 void no_ack_irq(unsigned int irq);
 void no_end_irq(unsigned int irq);
+void cpu_ack_irq(unsigned int irq);
+void cpu_end_irq(unsigned int irq);
 
 extern int txn_alloc_irq(unsigned int nbits);
 extern int txn_claim_irq(int);
@@ -46,7 +48,7 @@
 extern unsigned long txn_alloc_addr(unsigned int);
 extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
 
-extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
+extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
 extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest);
 
 /* soft power switch support (power.c) */
diff --git a/include/asm-parisc/mckinley.h b/include/asm-parisc/mckinley.h
new file mode 100644
index 0000000..d1ea6f1
--- /dev/null
+++ b/include/asm-parisc/mckinley.h
@@ -0,0 +1,9 @@
+#ifndef ASM_PARISC_MCKINLEY_H
+#define ASM_PARISC_MCKINLEY_H
+#ifdef __KERNEL__
+
+/* declared in arch/parisc/kernel/setup.c */
+extern struct proc_dir_entry * proc_mckinley_root;
+
+#endif /*__KERNEL__*/
+#endif /*ASM_PARISC_MCKINLEY_H*/
diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
index 57d6d82..3567208 100644
--- a/include/asm-parisc/page.h
+++ b/include/asm-parisc/page.h
@@ -26,24 +26,10 @@
 
 struct page;
 
-extern void purge_kernel_dcache_page(unsigned long);
-extern void copy_user_page_asm(void *to, void *from);
-extern void clear_user_page_asm(void *page, unsigned long vaddr);
-
-static inline void
-copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg)
-{
-	copy_user_page_asm(vto, vfrom);
-	flush_kernel_dcache_page_asm(vto);
-	/* XXX: ppc flushes icache too, should we? */
-}
-
-static inline void
-clear_user_page(void *page, unsigned long vaddr, struct page *pg)
-{
-	purge_kernel_dcache_page((unsigned long)page);
-	clear_user_page_asm(page, vaddr);
-}
+void copy_user_page_asm(void *to, void *from);
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+			   struct page *pg);
+void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
 
 /*
  * These are used to make use of C type-checking..
diff --git a/include/asm-parisc/param.h b/include/asm-parisc/param.h
index 07cb9b93..32e03d8 100644
--- a/include/asm-parisc/param.h
+++ b/include/asm-parisc/param.h
@@ -2,13 +2,9 @@
 #define _ASMPARISC_PARAM_H
 
 #ifdef __KERNEL__
-# ifdef CONFIG_PA20
-#  define HZ		1000		/* Faster machines */
-# else
-#  define HZ		100		/* Internal kernel timer frequency */
-# endif
-# define USER_HZ	100		/* .. some user interfaces are in "ticks" */
-# define CLOCKS_PER_SEC	(USER_HZ)	/* like times() */
+#define HZ		CONFIG_HZ
+#define USER_HZ		100		/* some user API use "ticks" */
+#define CLOCKS_PER_SEC	(USER_HZ)	/* like times() */
 #endif
 
 #ifndef HZ
diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h
index 1d247e3..e12624d 100644
--- a/include/asm-parisc/parisc-device.h
+++ b/include/asm-parisc/parisc-device.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_PARISC_PARISC_DEVICE_H_
+#define _ASM_PARISC_PARISC_DEVICE_H_
+
 #include <linux/device.h>
 
 struct parisc_device {
@@ -57,3 +60,5 @@
 }
 
 extern struct bus_type parisc_bus_type;
+
+#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
index 8b631f4..7b8ad11 100644
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -293,4 +293,9 @@
 	/* We don't need to penalize isa irq's */
 }
 
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+	return channel ? 15 : 14;
+}
+
 #endif /* __ASM_PARISC_PCI_H */
diff --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h
new file mode 100644
index 0000000..5d02172
--- /dev/null
+++ b/include/asm-parisc/prefetch.h
@@ -0,0 +1,39 @@
+/*
+ * include/asm-parisc/prefetch.h
+ *
+ * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
+ * In addition, many implementations do hardware prefetching of both
+ * instructions and data.
+ *
+ * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
+ * to gr0 but not in a way that Linux can use.  If the load would cause an
+ * interruption (eg due to prefetching 0), it is suppressed on PA2.0
+ * processors, but not on 7300LC.
+ *
+ */
+
+#ifndef __ASM_PARISC_PREFETCH_H
+#define __ASM_PARISC_PREFETCH_H
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_PREFETCH
+
+#define ARCH_HAS_PREFETCH
+extern inline void prefetch(const void *addr)
+{
+	__asm__("ldw 0(%0), %%r0" : : "r" (addr));
+}
+
+/* LDD is a PA2.0 addition. */
+#ifdef CONFIG_PA20
+#define ARCH_HAS_PREFETCHW
+extern inline void prefetchw(const void *addr)
+{
+	__asm__("ldd 0(%0), %%r0" : : "r" (addr));
+}
+#endif /* CONFIG_PA20 */
+
+#endif /* CONFIG_PREFETCH */
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
index b73626f..fd7866d 100644
--- a/include/asm-parisc/processor.h
+++ b/include/asm-parisc/processor.h
@@ -9,6 +9,8 @@
 #define __ASM_PARISC_PROCESSOR_H
 
 #ifndef __ASSEMBLY__
+#include <asm/prefetch.h>	/* lockdep.h needs <linux/prefetch.h> */
+
 #include <linux/threads.h>
 #include <linux/spinlock_types.h>
 
@@ -276,7 +278,7 @@
  */
 
 #ifdef __LP64__
-#define USER_WIDE_MODE	(personality(current->personality) == PER_LINUX)
+#define USER_WIDE_MODE	(!test_thread_flag(TIF_32BIT))
 #else
 #define USER_WIDE_MODE	0
 #endif
@@ -328,34 +330,21 @@
 #define KSTK_EIP(tsk)	((tsk)->thread.regs.iaoq[0])
 #define KSTK_ESP(tsk)	((tsk)->thread.regs.gr[30])
 
-
-/*
- * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
- * In addition, many implementations do hardware prefetching of both
- * instructions and data.
- *
- * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
- * to gr0 but not in a way that Linux can use.  If the load would cause an
- * interruption (eg due to prefetching 0), it is suppressed on PA2.0
- * processors, but not on 7300LC.
- */
-#ifdef  CONFIG_PREFETCH
-#define ARCH_HAS_PREFETCH
-#define ARCH_HAS_PREFETCHW
-
-extern inline void prefetch(const void *addr)
-{
-	__asm__("ldw 0(%0), %%r0" : : "r" (addr));
-}
-
-extern inline void prefetchw(const void *addr)
-{
-	__asm__("ldd 0(%0), %%r0" : : "r" (addr));
-}
-#endif
-
 #define cpu_relax()	barrier()
 
+/* Used as a macro to identify the combined VIPT/PIPT cached
+ * CPUs which require a guarantee of coherency (no inequivalent
+ * aliases with different data, whether clean or not) to operate */
+static inline int parisc_requires_coherency(void)
+{
+#ifdef CONFIG_PA8X00
+	/* FIXME: also pa8900 - when we see one */
+	return boot_cpu_data.cpu_type == mako;
+#else
+	return 0;
+#endif
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h
new file mode 100644
index 0000000..5542dd0
--- /dev/null
+++ b/include/asm-parisc/ropes.h
@@ -0,0 +1,322 @@
+#ifndef _ASM_PARISC_ROPES_H_
+#define _ASM_PARISC_ROPES_H_
+
+#include <asm-parisc/parisc-device.h>
+
+#ifdef CONFIG_64BIT
+/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
+#define ZX1_SUPPORT
+#endif
+
+#ifdef CONFIG_PROC_FS
+/* depends on proc fs support. But costs CPU performance */
+#undef SBA_COLLECT_STATS
+#endif
+
+/*
+** The number of pdir entries to "free" before issueing
+** a read to PCOM register to flush out PCOM writes.
+** Interacts with allocation granularity (ie 4 or 8 entries
+** allocated and free'd/purged at a time might make this
+** less interesting).
+*/
+#define DELAYED_RESOURCE_CNT	16
+
+#define MAX_IOC		2	/* per Ike. Pluto/Astro only have 1. */
+#define ROPES_PER_IOC	8	/* per Ike half or Pluto/Astro */
+
+struct ioc {
+	void __iomem	*ioc_hpa;	/* I/O MMU base address */
+	char		*res_map;	/* resource map, bit == pdir entry */
+	u64		*pdir_base;	/* physical base address */
+	unsigned long	ibase;		/* pdir IOV Space base - shared w/lba_pci */
+	unsigned long	imask;		/* pdir IOV Space mask - shared w/lba_pci */
+#ifdef ZX1_SUPPORT
+	unsigned long	iovp_mask;	/* help convert IOVA to IOVP */
+#endif
+	unsigned long	*res_hint;	/* next avail IOVP - circular search */
+	spinlock_t	res_lock;
+	unsigned int	res_bitshift;	/* from the LEFT! */
+	unsigned int	res_size;	/* size of resource map in bytes */
+#ifdef SBA_HINT_SUPPORT
+/* FIXME : DMA HINTs not used */
+	unsigned long	hint_mask_pdir; /* bits used for DMA hints */
+	unsigned int	hint_shift_pdir;
+#endif
+#if DELAYED_RESOURCE_CNT > 0
+	int		saved_cnt;
+	struct sba_dma_pair {
+			dma_addr_t	iova;
+			size_t		size;
+        } saved[DELAYED_RESOURCE_CNT];
+#endif
+
+#ifdef SBA_COLLECT_STATS
+#define SBA_SEARCH_SAMPLE	0x100
+	unsigned long	avg_search[SBA_SEARCH_SAMPLE];
+	unsigned long	avg_idx;	/* current index into avg_search */
+	unsigned long	used_pages;
+	unsigned long	msingle_calls;
+	unsigned long	msingle_pages;
+	unsigned long	msg_calls;
+	unsigned long	msg_pages;
+	unsigned long	usingle_calls;
+	unsigned long	usingle_pages;
+	unsigned long	usg_calls;
+	unsigned long	usg_pages;
+#endif
+        /* STUFF We don't need in performance path */
+	unsigned int	pdir_size;	/* in bytes, determined by IOV Space size */
+};
+
+struct sba_device {
+	struct sba_device	*next;  /* list of SBA's in system */
+	struct parisc_device	*dev;   /* dev found in bus walk */
+	const char		*name;
+	void __iomem		*sba_hpa; /* base address */
+	spinlock_t		sba_lock;
+	unsigned int		flags;  /* state/functionality enabled */
+	unsigned int		hw_rev;  /* HW revision of chip */
+
+	struct resource		chip_resv; /* MMIO reserved for chip */
+	struct resource		iommu_resv; /* MMIO reserved for iommu */
+
+	unsigned int		num_ioc;  /* number of on-board IOC's */
+	struct ioc		ioc[MAX_IOC];
+};
+
+#define ASTRO_RUNWAY_PORT	0x582
+#define IKE_MERCED_PORT		0x803
+#define REO_MERCED_PORT		0x804
+#define REOG_MERCED_PORT	0x805
+#define PLUTO_MCKINLEY_PORT	0x880
+
+static inline int IS_ASTRO(struct parisc_device *d) {
+	return d->id.hversion == ASTRO_RUNWAY_PORT;
+}
+
+static inline int IS_IKE(struct parisc_device *d) {
+	return d->id.hversion == IKE_MERCED_PORT;
+}
+
+static inline int IS_PLUTO(struct parisc_device *d) {
+	return d->id.hversion == PLUTO_MCKINLEY_PORT;
+}
+
+#define PLUTO_IOVA_BASE	(1UL*1024*1024*1024)	/* 1GB */
+#define PLUTO_IOVA_SIZE	(1UL*1024*1024*1024)	/* 1GB */
+#define PLUTO_GART_SIZE	(PLUTO_IOVA_SIZE / 2)
+
+#define SBA_PDIR_VALID_BIT	0x8000000000000000ULL
+
+#define SBA_AGPGART_COOKIE	0x0000badbadc0ffeeULL
+
+#define SBA_FUNC_ID	0x0000	/* function id */
+#define SBA_FCLASS	0x0008	/* function class, bist, header, rev... */
+
+#define SBA_FUNC_SIZE 4096   /* SBA configuration function reg set */
+
+#define ASTRO_IOC_OFFSET	(32 * SBA_FUNC_SIZE)
+#define PLUTO_IOC_OFFSET	(1 * SBA_FUNC_SIZE)
+/* Ike's IOC's occupy functions 2 and 3 */
+#define IKE_IOC_OFFSET(p)	((p+2) * SBA_FUNC_SIZE)
+
+#define IOC_CTRL          0x8	/* IOC_CTRL offset */
+#define IOC_CTRL_TC       (1 << 0) /* TOC Enable */
+#define IOC_CTRL_CE       (1 << 1) /* Coalesce Enable */
+#define IOC_CTRL_DE       (1 << 2) /* Dillon Enable */
+#define IOC_CTRL_RM       (1 << 8) /* Real Mode */
+#define IOC_CTRL_NC       (1 << 9) /* Non Coherent Mode */
+#define IOC_CTRL_D4       (1 << 11) /* Disable 4-byte coalescing */
+#define IOC_CTRL_DD       (1 << 13) /* Disable distr. LMMIO range coalescing */
+
+/*
+** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
+** Firmware programs this stuff. Don't touch it.
+*/
+#define LMMIO_DIRECT0_BASE  0x300
+#define LMMIO_DIRECT0_MASK  0x308
+#define LMMIO_DIRECT0_ROUTE 0x310
+
+#define LMMIO_DIST_BASE  0x360
+#define LMMIO_DIST_MASK  0x368
+#define LMMIO_DIST_ROUTE 0x370
+
+#define IOS_DIST_BASE	0x390
+#define IOS_DIST_MASK	0x398
+#define IOS_DIST_ROUTE	0x3A0
+
+#define IOS_DIRECT_BASE	0x3C0
+#define IOS_DIRECT_MASK	0x3C8
+#define IOS_DIRECT_ROUTE 0x3D0
+
+/*
+** Offsets into I/O TLB (Function 2 and 3 on Ike)
+*/
+#define ROPE0_CTL	0x200  /* "regbus pci0" */
+#define ROPE1_CTL	0x208
+#define ROPE2_CTL	0x210
+#define ROPE3_CTL	0x218
+#define ROPE4_CTL	0x220
+#define ROPE5_CTL	0x228
+#define ROPE6_CTL	0x230
+#define ROPE7_CTL	0x238
+
+#define IOC_ROPE0_CFG	0x500	/* pluto only */
+#define   IOC_ROPE_AO	  0x10	/* Allow "Relaxed Ordering" */
+
+#define HF_ENABLE	0x40
+
+#define IOC_IBASE	0x300	/* IO TLB */
+#define IOC_IMASK	0x308
+#define IOC_PCOM	0x310
+#define IOC_TCNFG	0x318
+#define IOC_PDIR_BASE	0x320
+
+/*
+** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+** It's safer (avoid memory corruption) to keep DMA page mappings
+** equivalently sized to VM PAGE_SIZE.
+**
+** We really can't avoid generating a new mapping for each
+** page since the Virtual Coherence Index has to be generated
+** and updated for each page.
+**
+** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
+*/
+#define IOVP_SIZE	PAGE_SIZE
+#define IOVP_SHIFT	PAGE_SHIFT
+#define IOVP_MASK	PAGE_MASK
+
+#define SBA_PERF_CFG	0x708	/* Performance Counter stuff */
+#define SBA_PERF_MASK1	0x718
+#define SBA_PERF_MASK2	0x730
+
+/*
+** Offsets into PCI Performance Counters (functions 12 and 13)
+** Controlled by PERF registers in function 2 & 3 respectively.
+*/
+#define SBA_PERF_CNT1	0x200
+#define SBA_PERF_CNT2	0x208
+#define SBA_PERF_CNT3	0x210
+
+/*
+** lba_device: Per instance Elroy data structure
+*/
+struct lba_device {
+	struct pci_hba_data	hba;
+
+	spinlock_t		lba_lock;
+	void			*iosapic_obj;
+
+#ifdef CONFIG_64BIT
+	void __iomem		*iop_base;	/* PA_VIEW - for IO port accessor funcs */
+#endif
+
+	int			flags;		/* state/functionality enabled */
+	int			hw_rev;		/* HW revision of chip */
+};
+
+#define ELROY_HVERS		0x782
+#define MERCURY_HVERS		0x783
+#define QUICKSILVER_HVERS	0x784
+
+static inline int IS_ELROY(struct parisc_device *d) {
+	return (d->id.hversion == ELROY_HVERS);
+}
+
+static inline int IS_MERCURY(struct parisc_device *d) {
+	return (d->id.hversion == MERCURY_HVERS);
+}
+
+static inline int IS_QUICKSILVER(struct parisc_device *d) {
+	return (d->id.hversion == QUICKSILVER_HVERS);
+}
+
+static inline int agp_mode_mercury(void __iomem *hpa) {
+	u64 bus_mode;
+
+	bus_mode = readl(hpa + 0x0620);
+	if (bus_mode & 1)
+		return 1;
+
+	return 0;
+}
+
+/*
+** I/O SAPIC init function
+** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
+** Call setup as part of per instance initialization.
+** (ie *not* init_module() function unless only one is present.)
+** fixup_irq is to initialize PCI IRQ line support and
+** virtualize pcidev->irq value. To be called by pci_fixup_bus().
+*/
+extern void *iosapic_register(unsigned long hpa);
+extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
+
+#define LBA_FUNC_ID	0x0000	/* function id */
+#define LBA_FCLASS	0x0008	/* function class, bist, header, rev... */
+#define LBA_CAPABLE	0x0030	/* capabilities register */
+
+#define LBA_PCI_CFG_ADDR	0x0040	/* poke CFG address here */
+#define LBA_PCI_CFG_DATA	0x0048	/* read or write data here */
+
+#define LBA_PMC_MTLT	0x0050	/* Firmware sets this - read only. */
+#define LBA_FW_SCRATCH	0x0058	/* Firmware writes the PCI bus number here. */
+#define LBA_ERROR_ADDR	0x0070	/* On error, address gets logged here */
+
+#define LBA_ARB_MASK	0x0080	/* bit 0 enable arbitration. PAT/PDC enables */
+#define LBA_ARB_PRI	0x0088	/* firmware sets this. */
+#define LBA_ARB_MODE	0x0090	/* firmware sets this. */
+#define LBA_ARB_MTLT	0x0098	/* firmware sets this. */
+
+#define LBA_MOD_ID	0x0100	/* Module ID. PDC_PAT_CELL reports 4 */
+
+#define LBA_STAT_CTL	0x0108	/* Status & Control */
+#define   LBA_BUS_RESET		0x01	/*  Deassert PCI Bus Reset Signal */
+#define   CLEAR_ERRLOG		0x10	/*  "Clear Error Log" cmd */
+#define   CLEAR_ERRLOG_ENABLE	0x20	/*  "Clear Error Log" Enable */
+#define   HF_ENABLE	0x40	/*    enable HF mode (default is -1 mode) */
+
+#define LBA_LMMIO_BASE	0x0200	/* < 4GB I/O address range */
+#define LBA_LMMIO_MASK	0x0208
+
+#define LBA_GMMIO_BASE	0x0210	/* > 4GB I/O address range */
+#define LBA_GMMIO_MASK	0x0218
+
+#define LBA_WLMMIO_BASE	0x0220	/* All < 4GB ranges under the same *SBA* */
+#define LBA_WLMMIO_MASK	0x0228
+
+#define LBA_WGMMIO_BASE	0x0230	/* All > 4GB ranges under the same *SBA* */
+#define LBA_WGMMIO_MASK	0x0238
+
+#define LBA_IOS_BASE	0x0240	/* I/O port space for this LBA */
+#define LBA_IOS_MASK	0x0248
+
+#define LBA_ELMMIO_BASE	0x0250	/* Extra LMMIO range */
+#define LBA_ELMMIO_MASK	0x0258
+
+#define LBA_EIOS_BASE	0x0260	/* Extra I/O port space */
+#define LBA_EIOS_MASK	0x0268
+
+#define LBA_GLOBAL_MASK	0x0270	/* Mercury only: Global Address Mask */
+#define LBA_DMA_CTL	0x0278	/* firmware sets this */
+
+#define LBA_IBASE	0x0300	/* SBA DMA support */
+#define LBA_IMASK	0x0308
+
+/* FIXME: ignore DMA Hint stuff until we can measure performance */
+#define LBA_HINT_CFG	0x0310
+#define LBA_HINT_BASE	0x0380	/* 14 registers at every 8 bytes. */
+
+#define LBA_BUS_MODE	0x0620
+
+/* ERROR regs are needed for config cycle kluges */
+#define LBA_ERROR_CONFIG 0x0680
+#define     LBA_SMART_MODE 0x20
+#define LBA_ERROR_STATUS 0x0688
+#define LBA_ROPE_CTL     0x06A0
+
+#define LBA_IOSAPIC_BASE	0x800 /* Offset of IRQ logic */
+
+#endif /*_ASM_PARISC_ROPES_H_*/
diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
index 82fd820..d7e3cc6 100644
--- a/include/asm-parisc/serial.h
+++ b/include/asm-parisc/serial.h
@@ -3,20 +3,8 @@
  */
 
 /*
- * This assumes you have a 7.272727 MHz clock for your UART.
- * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
- * Clarified: 7.2727MHz on LASI. Not yet clarified for DINO
+ * This is used for 16550-compatible UARTs
  */
+#define BASE_BAUD ( 1843200 / 16 )
 
-#define LASI_BASE_BAUD ( 7272727 / 16 )
-#define BASE_BAUD  LASI_BASE_BAUD
-
-/*
- * We don't use the ISA probing code, so these entries are just to reserve
- * space.  Some example (maximal) configurations:
- * - 712 w/ additional Lasi & RJ16 ports: 4
- * - J5k w/ PCI serial cards: 2 + 4 * card ~= 34
- * A500 w/ PCI serial cards: 5 + 4 * card ~= 17
- */
- 
 #define SERIAL_PORT_DFNS
diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h
index e182553..f3d2090 100644
--- a/include/asm-parisc/spinlock.h
+++ b/include/asm-parisc/spinlock.h
@@ -56,50 +56,79 @@
 }
 
 /*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Linux rwlocks are unfair to writers; they can be starved for an indefinite
+ * time by readers.  With care, they can also be taken in interrupt context.
+ *
+ * In the PA-RISC implementation, we have a spinlock and a counter.
+ * Readers use the lock to serialise their access to the counter (which
+ * records how many readers currently hold the lock).
+ * Writers hold the spinlock, preventing any readers or other writers from
+ * grabbing the rwlock.
  */
 
-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
-
-/* read_lock, read_unlock are pretty straightforward.  Of course it somehow
- * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
-
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock */
 static  __inline__ void __raw_read_lock(raw_rwlock_t *rw)
 {
-	__raw_spin_lock(&rw->lock);
-
+	unsigned long flags;
+	local_irq_save(flags);
+	__raw_spin_lock_flags(&rw->lock, flags);
 	rw->counter++;
-
 	__raw_spin_unlock(&rw->lock);
+	local_irq_restore(flags);
 }
 
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock */
 static  __inline__ void __raw_read_unlock(raw_rwlock_t *rw)
 {
-	__raw_spin_lock(&rw->lock);
-
+	unsigned long flags;
+	local_irq_save(flags);
+	__raw_spin_lock_flags(&rw->lock, flags);
 	rw->counter--;
-
 	__raw_spin_unlock(&rw->lock);
+	local_irq_restore(flags);
 }
 
-/* write_lock is less trivial.  We optimistically grab the lock and check
- * if we surprised any readers.  If so we release the lock and wait till
- * they're all gone before trying again
- *
- * Also note that we don't use the _irqsave / _irqrestore suffixes here.
- * If we're called with interrupts enabled and we've got readers (or other
- * writers) in interrupt handlers someone fucked up and we'd dead-lock
- * sooner or later anyway.   prumpf */
-
-static  __inline__ void __raw_write_lock(raw_rwlock_t *rw)
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock */
+static __inline__ int __raw_read_trylock(raw_rwlock_t *rw)
 {
-retry:
-	__raw_spin_lock(&rw->lock);
-
-	if(rw->counter != 0) {
-		/* this basically never happens */
+	unsigned long flags;
+ retry:
+	local_irq_save(flags);
+	if (__raw_spin_trylock(&rw->lock)) {
+		rw->counter++;
 		__raw_spin_unlock(&rw->lock);
+		local_irq_restore(flags);
+		return 1;
+	}
+
+	local_irq_restore(flags);
+	/* If write-locked, we fail to acquire the lock */
+	if (rw->counter < 0)
+		return 0;
+
+	/* Wait until we have a realistic chance at the lock */
+	while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0)
+		cpu_relax();
+
+	goto retry;
+}
+
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to read_trylock() this lock */
+static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
+{
+	unsigned long flags;
+retry:
+	local_irq_save(flags);
+	__raw_spin_lock_flags(&rw->lock, flags);
+
+	if (rw->counter != 0) {
+		__raw_spin_unlock(&rw->lock);
+		local_irq_restore(flags);
 
 		while (rw->counter != 0)
 			cpu_relax();
@@ -107,31 +136,37 @@
 		goto retry;
 	}
 
-	/* got it.  now leave without unlocking */
-	rw->counter = -1; /* remember we are locked */
+	rw->counter = -1; /* mark as write-locked */
+	mb();
+	local_irq_restore(flags);
 }
 
-/* write_unlock is absolutely trivial - we don't have to wait for anything */
-
-static  __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
+static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
 {
 	rw->counter = 0;
 	__raw_spin_unlock(&rw->lock);
 }
 
-static  __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to read_trylock() this lock */
+static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
 {
-	__raw_spin_lock(&rw->lock);
-	if (rw->counter != 0) {
-		/* this basically never happens */
-		__raw_spin_unlock(&rw->lock);
+	unsigned long flags;
+	int result = 0;
 
-		return 0;
+	local_irq_save(flags);
+	if (__raw_spin_trylock(&rw->lock)) {
+		if (rw->counter == 0) {
+			rw->counter = -1;
+			result = 1;
+		} else {
+			/* Read-locked.  Oh well. */
+			__raw_spin_unlock(&rw->lock);
+		}
 	}
+	local_irq_restore(flags);
 
-	/* got it.  now leave without unlocking */
-	rw->counter = -1; /* remember we are locked */
-	return 1;
+	return result;
 }
 
 /*
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index 77069df..1022737 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -14,34 +14,36 @@
 
 #ifdef __KERNEL__
 
-#ifndef __ASSEMBLY__
+#include <asm/asm-compat.h>
 
 /* firmware feature bitmask values */
 #define FIRMWARE_MAX_FEATURES 63
 
-#define FW_FEATURE_PFT		(1UL<<0)
-#define FW_FEATURE_TCE		(1UL<<1)
-#define FW_FEATURE_SPRG0	(1UL<<2)
-#define FW_FEATURE_DABR		(1UL<<3)
-#define FW_FEATURE_COPY		(1UL<<4)
-#define FW_FEATURE_ASR		(1UL<<5)
-#define FW_FEATURE_DEBUG	(1UL<<6)
-#define FW_FEATURE_TERM		(1UL<<7)
-#define FW_FEATURE_PERF		(1UL<<8)
-#define FW_FEATURE_DUMP		(1UL<<9)
-#define FW_FEATURE_INTERRUPT	(1UL<<10)
-#define FW_FEATURE_MIGRATE	(1UL<<11)
-#define FW_FEATURE_PERFMON	(1UL<<12)
-#define FW_FEATURE_CRQ		(1UL<<13)
-#define FW_FEATURE_VIO		(1UL<<14)
-#define FW_FEATURE_RDMA		(1UL<<15)
-#define FW_FEATURE_LLAN		(1UL<<16)
-#define FW_FEATURE_BULK		(1UL<<17)
-#define FW_FEATURE_XDABR	(1UL<<18)
-#define FW_FEATURE_MULTITCE	(1UL<<19)
-#define FW_FEATURE_SPLPAR	(1UL<<20)
-#define FW_FEATURE_ISERIES	(1UL<<21)
-#define FW_FEATURE_LPAR		(1UL<<22)
+#define FW_FEATURE_PFT		ASM_CONST(0x0000000000000001)
+#define FW_FEATURE_TCE		ASM_CONST(0x0000000000000002)
+#define FW_FEATURE_SPRG0	ASM_CONST(0x0000000000000004)
+#define FW_FEATURE_DABR		ASM_CONST(0x0000000000000008)
+#define FW_FEATURE_COPY		ASM_CONST(0x0000000000000010)
+#define FW_FEATURE_ASR		ASM_CONST(0x0000000000000020)
+#define FW_FEATURE_DEBUG	ASM_CONST(0x0000000000000040)
+#define FW_FEATURE_TERM		ASM_CONST(0x0000000000000080)
+#define FW_FEATURE_PERF		ASM_CONST(0x0000000000000100)
+#define FW_FEATURE_DUMP		ASM_CONST(0x0000000000000200)
+#define FW_FEATURE_INTERRUPT	ASM_CONST(0x0000000000000400)
+#define FW_FEATURE_MIGRATE	ASM_CONST(0x0000000000000800)
+#define FW_FEATURE_PERFMON	ASM_CONST(0x0000000000001000)
+#define FW_FEATURE_CRQ		ASM_CONST(0x0000000000002000)
+#define FW_FEATURE_VIO		ASM_CONST(0x0000000000004000)
+#define FW_FEATURE_RDMA		ASM_CONST(0x0000000000008000)
+#define FW_FEATURE_LLAN		ASM_CONST(0x0000000000010000)
+#define FW_FEATURE_BULK		ASM_CONST(0x0000000000020000)
+#define FW_FEATURE_XDABR	ASM_CONST(0x0000000000040000)
+#define FW_FEATURE_MULTITCE	ASM_CONST(0x0000000000080000)
+#define FW_FEATURE_SPLPAR	ASM_CONST(0x0000000000100000)
+#define FW_FEATURE_ISERIES	ASM_CONST(0x0000000000200000)
+#define FW_FEATURE_LPAR		ASM_CONST(0x0000000000400000)
+
+#ifndef __ASSEMBLY__
 
 enum {
 #ifdef CONFIG_PPC64
@@ -94,6 +96,23 @@
 /* This is true if we are using the firmware NMI handler (typically LPAR) */
 extern int fwnmi_active;
 
+#else /* __ASSEMBLY__ */
+
+#define BEGIN_FW_FTR_SECTION		96:
+
+#define END_FW_FTR_SECTION(msk, val)		\
+97:						\
+	.section __fw_ftr_fixup,"a";		\
+	.align 3;				\
+	.llong msk;				\
+	.llong val;				\
+	.llong 96b;				\
+	.llong 97b;				\
+	.previous
+
+#define END_FW_FTR_SECTION_IFSET(msk)	END_FW_FTR_SECTION((msk), (msk))
+#define END_FW_FTR_SECTION_IFCLR(msk)	END_FW_FTR_SECTION((msk), 0)
+
 #endif /* __ASSEMBLY__ */
 #endif /* __KERNEL__ */
 #endif /* __ASM_POWERPC_FIRMWARE_H */
diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h
new file mode 100644
index 0000000..ce12f85
--- /dev/null
+++ b/include/asm-powerpc/immap_qe.h
@@ -0,0 +1,477 @@
+/*
+ * include/asm-powerpc/immap_qe.h
+ *
+ * QUICC Engine (QE) Internal Memory Map.
+ * The Internal Memory Map for devices with QE on them. This
+ * is the superset of all QE devices (8360, etc.).
+
+ * Copyright (C) 2006. Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASM_POWERPC_IMMAP_QE_H
+#define _ASM_POWERPC_IMMAP_QE_H
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+
+#define QE_IMMAP_SIZE	(1024 * 1024)	/* 1MB from 1MB+IMMR */
+
+/* QE I-RAM */
+struct qe_iram {
+	__be32	iadd;		/* I-RAM Address Register */
+	__be32	idata;		/* I-RAM Data Register */
+	u8	res0[0x78];
+} __attribute__ ((packed));
+
+/* QE Interrupt Controller */
+struct qe_ic_regs {
+	__be32	qicr;
+	__be32	qivec;
+	__be32	qripnr;
+	__be32	qipnr;
+	__be32	qipxcc;
+	__be32	qipycc;
+	__be32	qipwcc;
+	__be32	qipzcc;
+	__be32	qimr;
+	__be32	qrimr;
+	__be32	qicnr;
+	u8	res0[0x4];
+	__be32	qiprta;
+	__be32	qiprtb;
+	u8	res1[0x4];
+	__be32	qricr;
+	u8	res2[0x20];
+	__be32	qhivec;
+	u8	res3[0x1C];
+} __attribute__ ((packed));
+
+/* Communications Processor */
+struct cp_qe {
+	__be32	cecr;		/* QE command register */
+	__be32	ceccr;		/* QE controller configuration register */
+	__be32	cecdr;		/* QE command data register */
+	u8	res0[0xA];
+	__be16	ceter;		/* QE timer event register */
+	u8	res1[0x2];
+	__be16	cetmr;		/* QE timers mask register */
+	__be32	cetscr;		/* QE time-stamp timer control register */
+	__be32	cetsr1;		/* QE time-stamp register 1 */
+	__be32	cetsr2;		/* QE time-stamp register 2 */
+	u8	res2[0x8];
+	__be32	cevter;		/* QE virtual tasks event register */
+	__be32	cevtmr;		/* QE virtual tasks mask register */
+	__be16	cercr;		/* QE RAM control register */
+	u8	res3[0x2];
+	u8	res4[0x24];
+	__be16	ceexe1;		/* QE external request 1 event register */
+	u8	res5[0x2];
+	__be16	ceexm1;		/* QE external request 1 mask register */
+	u8	res6[0x2];
+	__be16	ceexe2;		/* QE external request 2 event register */
+	u8	res7[0x2];
+	__be16	ceexm2;		/* QE external request 2 mask register */
+	u8	res8[0x2];
+	__be16	ceexe3;		/* QE external request 3 event register */
+	u8	res9[0x2];
+	__be16	ceexm3;		/* QE external request 3 mask register */
+	u8	res10[0x2];
+	__be16	ceexe4;		/* QE external request 4 event register */
+	u8	res11[0x2];
+	__be16	ceexm4;		/* QE external request 4 mask register */
+	u8	res12[0x2];
+	u8	res13[0x280];
+} __attribute__ ((packed));
+
+/* QE Multiplexer */
+struct qe_mux {
+	__be32	cmxgcr;		/* CMX general clock route register */
+	__be32	cmxsi1cr_l;	/* CMX SI1 clock route low register */
+	__be32	cmxsi1cr_h;	/* CMX SI1 clock route high register */
+	__be32	cmxsi1syr;	/* CMX SI1 SYNC route register */
+	__be32	cmxucr1;	/* CMX UCC1, UCC3 clock route register */
+	__be32	cmxucr2;	/* CMX UCC5, UCC7 clock route register */
+	__be32	cmxucr3;	/* CMX UCC2, UCC4 clock route register */
+	__be32	cmxucr4;	/* CMX UCC6, UCC8 clock route register */
+	__be32	cmxupcr;	/* CMX UPC clock route register */
+	u8	res0[0x1C];
+} __attribute__ ((packed));
+
+/* QE Timers */
+struct qe_timers {
+	u8	gtcfr1;		/* Timer 1 and Timer 2 global config register*/
+	u8	res0[0x3];
+	u8	gtcfr2;		/* Timer 3 and timer 4 global config register*/
+	u8	res1[0xB];
+	__be16	gtmdr1;		/* Timer 1 mode register */
+	__be16	gtmdr2;		/* Timer 2 mode register */
+	__be16	gtrfr1;		/* Timer 1 reference register */
+	__be16	gtrfr2;		/* Timer 2 reference register */
+	__be16	gtcpr1;		/* Timer 1 capture register */
+	__be16	gtcpr2;		/* Timer 2 capture register */
+	__be16	gtcnr1;		/* Timer 1 counter */
+	__be16	gtcnr2;		/* Timer 2 counter */
+	__be16	gtmdr3;		/* Timer 3 mode register */
+	__be16	gtmdr4;		/* Timer 4 mode register */
+	__be16	gtrfr3;		/* Timer 3 reference register */
+	__be16	gtrfr4;		/* Timer 4 reference register */
+	__be16	gtcpr3;		/* Timer 3 capture register */
+	__be16	gtcpr4;		/* Timer 4 capture register */
+	__be16	gtcnr3;		/* Timer 3 counter */
+	__be16	gtcnr4;		/* Timer 4 counter */
+	__be16	gtevr1;		/* Timer 1 event register */
+	__be16	gtevr2;		/* Timer 2 event register */
+	__be16	gtevr3;		/* Timer 3 event register */
+	__be16	gtevr4;		/* Timer 4 event register */
+	__be16	gtps;		/* Timer 1 prescale register */
+	u8 res2[0x46];
+} __attribute__ ((packed));
+
+/* BRG */
+struct qe_brg {
+	__be32	brgc1;		/* BRG1 configuration register */
+	__be32	brgc2;		/* BRG2 configuration register */
+	__be32	brgc3;		/* BRG3 configuration register */
+	__be32	brgc4;		/* BRG4 configuration register */
+	__be32	brgc5;		/* BRG5 configuration register */
+	__be32	brgc6;		/* BRG6 configuration register */
+	__be32	brgc7;		/* BRG7 configuration register */
+	__be32	brgc8;		/* BRG8 configuration register */
+	__be32	brgc9;		/* BRG9 configuration register */
+	__be32	brgc10;		/* BRG10 configuration register */
+	__be32	brgc11;		/* BRG11 configuration register */
+	__be32	brgc12;		/* BRG12 configuration register */
+	__be32	brgc13;		/* BRG13 configuration register */
+	__be32	brgc14;		/* BRG14 configuration register */
+	__be32	brgc15;		/* BRG15 configuration register */
+	__be32	brgc16;		/* BRG16 configuration register */
+	u8	res0[0x40];
+} __attribute__ ((packed));
+
+/* SPI */
+struct spi {
+	u8	res0[0x20];
+	__be32	spmode;		/* SPI mode register */
+	u8	res1[0x2];
+	u8	spie;		/* SPI event register */
+	u8	res2[0x1];
+	u8	res3[0x2];
+	u8	spim;		/* SPI mask register */
+	u8	res4[0x1];
+	u8	res5[0x1];
+	u8	spcom;		/* SPI command register */
+	u8	res6[0x2];
+	__be32	spitd;		/* SPI transmit data register (cpu mode) */
+	__be32	spird;		/* SPI receive data register (cpu mode) */
+	u8	res7[0x8];
+} __attribute__ ((packed));
+
+/* SI */
+struct si1 {
+	__be16	siamr1;		/* SI1 TDMA mode register */
+	__be16	sibmr1;		/* SI1 TDMB mode register */
+	__be16	sicmr1;		/* SI1 TDMC mode register */
+	__be16	sidmr1;		/* SI1 TDMD mode register */
+	u8	siglmr1_h;	/* SI1 global mode register high */
+	u8	res0[0x1];
+	u8	sicmdr1_h;	/* SI1 command register high */
+	u8	res2[0x1];
+	u8	sistr1_h;	/* SI1 status register high */
+	u8	res3[0x1];
+	__be16	sirsr1_h;	/* SI1 RAM shadow address register high */
+	u8	sitarc1;	/* SI1 RAM counter Tx TDMA */
+	u8	sitbrc1;	/* SI1 RAM counter Tx TDMB */
+	u8	sitcrc1;	/* SI1 RAM counter Tx TDMC */
+	u8	sitdrc1;	/* SI1 RAM counter Tx TDMD */
+	u8	sirarc1;	/* SI1 RAM counter Rx TDMA */
+	u8	sirbrc1;	/* SI1 RAM counter Rx TDMB */
+	u8	sircrc1;	/* SI1 RAM counter Rx TDMC */
+	u8	sirdrc1;	/* SI1 RAM counter Rx TDMD */
+	u8	res4[0x8];
+	__be16	siemr1;		/* SI1 TDME mode register 16 bits */
+	__be16	sifmr1;		/* SI1 TDMF mode register 16 bits */
+	__be16	sigmr1;		/* SI1 TDMG mode register 16 bits */
+	__be16	sihmr1;		/* SI1 TDMH mode register 16 bits */
+	u8	siglmg1_l;	/* SI1 global mode register low 8 bits */
+	u8	res5[0x1];
+	u8	sicmdr1_l;	/* SI1 command register low 8 bits */
+	u8	res6[0x1];
+	u8	sistr1_l;	/* SI1 status register low 8 bits */
+	u8	res7[0x1];
+	__be16	sirsr1_l;	/* SI1 RAM shadow address register low 16 bits*/
+	u8	siterc1;	/* SI1 RAM counter Tx TDME 8 bits */
+	u8	sitfrc1;	/* SI1 RAM counter Tx TDMF 8 bits */
+	u8	sitgrc1;	/* SI1 RAM counter Tx TDMG 8 bits */
+	u8	sithrc1;	/* SI1 RAM counter Tx TDMH 8 bits */
+	u8	sirerc1;	/* SI1 RAM counter Rx TDME 8 bits */
+	u8	sirfrc1;	/* SI1 RAM counter Rx TDMF 8 bits */
+	u8	sirgrc1;	/* SI1 RAM counter Rx TDMG 8 bits */
+	u8	sirhrc1;	/* SI1 RAM counter Rx TDMH 8 bits */
+	u8	res8[0x8];
+	__be32	siml1;		/* SI1 multiframe limit register */
+	u8	siedm1;		/* SI1 extended diagnostic mode register */
+	u8	res9[0xBB];
+} __attribute__ ((packed));
+
+/* SI Routing Tables */
+struct sir {
+	u8 	tx[0x400];
+	u8	rx[0x400];
+	u8	res0[0x800];
+} __attribute__ ((packed));
+
+/* USB Controller */
+struct usb_ctlr {
+	u8	usb_usmod;
+	u8	usb_usadr;
+	u8	usb_uscom;
+	u8	res1[1];
+	__be16	usb_usep1;
+	__be16	usb_usep2;
+	__be16	usb_usep3;
+	__be16	usb_usep4;
+	u8	res2[4];
+	__be16	usb_usber;
+	u8	res3[2];
+	__be16	usb_usbmr;
+	u8	res4[1];
+	u8	usb_usbs;
+	__be16	usb_ussft;
+	u8	res5[2];
+	__be16	usb_usfrn;
+	u8	res6[0x22];
+} __attribute__ ((packed));
+
+/* MCC */
+struct mcc {
+	__be32	mcce;		/* MCC event register */
+	__be32	mccm;		/* MCC mask register */
+	__be32	mccf;		/* MCC configuration register */
+	__be32	merl;		/* MCC emergency request level register */
+	u8	res0[0xF0];
+} __attribute__ ((packed));
+
+/* QE UCC Slow */
+struct ucc_slow {
+	__be32	gumr_l;		/* UCCx general mode register (low) */
+	__be32	gumr_h;		/* UCCx general mode register (high) */
+	__be16	upsmr;		/* UCCx protocol-specific mode register */
+	u8	res0[0x2];
+	__be16	utodr;		/* UCCx transmit on demand register */
+	__be16	udsr;		/* UCCx data synchronization register */
+	__be16	ucce;		/* UCCx event register */
+	u8	res1[0x2];
+	__be16	uccm;		/* UCCx mask register */
+	u8	res2[0x1];
+	u8	uccs;		/* UCCx status register */
+	u8	res3[0x24];
+	__be16	utpt;
+	u8	guemr;		/* UCC general extended mode register */
+	u8	res4[0x200 - 0x091];
+} __attribute__ ((packed));
+
+/* QE UCC Fast */
+struct ucc_fast {
+	__be32	gumr;		/* UCCx general mode register */
+	__be32	upsmr;		/* UCCx protocol-specific mode register */
+	__be16	utodr;		/* UCCx transmit on demand register */
+	u8	res0[0x2];
+	__be16	udsr;		/* UCCx data synchronization register */
+	u8	res1[0x2];
+	__be32	ucce;		/* UCCx event register */
+	__be32	uccm;		/* UCCx mask register */
+	u8	uccs;		/* UCCx status register */
+	u8	res2[0x7];
+	__be32	urfb;		/* UCC receive FIFO base */
+	__be16	urfs;		/* UCC receive FIFO size */
+	u8	res3[0x2];
+	__be16	urfet;		/* UCC receive FIFO emergency threshold */
+	__be16	urfset;		/* UCC receive FIFO special emergency
+				   threshold */
+	__be32	utfb;		/* UCC transmit FIFO base */
+	__be16	utfs;		/* UCC transmit FIFO size */
+	u8	res4[0x2];
+	__be16	utfet;		/* UCC transmit FIFO emergency threshold */
+	u8	res5[0x2];
+	__be16	utftt;		/* UCC transmit FIFO transmit threshold */
+	u8	res6[0x2];
+	__be16	utpt;		/* UCC transmit polling timer */
+	u8	res7[0x2];
+	__be32	urtry;		/* UCC retry counter register */
+	u8	res8[0x4C];
+	u8	guemr;		/* UCC general extended mode register */
+	u8	res9[0x100 - 0x091];
+} __attribute__ ((packed));
+
+/* QE UCC */
+struct ucc_common {
+	u8	res1[0x90];
+	u8	guemr;
+	u8	res2[0x200 - 0x091];
+} __attribute__ ((packed));
+
+struct ucc {
+	union {
+		struct	ucc_slow slow;
+		struct	ucc_fast fast;
+		struct	ucc_common common;
+	};
+} __attribute__ ((packed));
+
+/* MultiPHY UTOPIA POS Controllers (UPC) */
+struct upc {
+	__be32	upgcr;		/* UTOPIA/POS general configuration register */
+	__be32	uplpa;		/* UTOPIA/POS last PHY address */
+	__be32	uphec;		/* ATM HEC register */
+	__be32	upuc;		/* UTOPIA/POS UCC configuration */
+	__be32	updc1;		/* UTOPIA/POS device 1 configuration */
+	__be32	updc2;		/* UTOPIA/POS device 2 configuration */
+	__be32	updc3;		/* UTOPIA/POS device 3 configuration */
+	__be32	updc4;		/* UTOPIA/POS device 4 configuration */
+	__be32	upstpa;		/* UTOPIA/POS STPA threshold */
+	u8	res0[0xC];
+	__be32	updrs1_h;	/* UTOPIA/POS device 1 rate select */
+	__be32	updrs1_l;	/* UTOPIA/POS device 1 rate select */
+	__be32	updrs2_h;	/* UTOPIA/POS device 2 rate select */
+	__be32	updrs2_l;	/* UTOPIA/POS device 2 rate select */
+	__be32	updrs3_h;	/* UTOPIA/POS device 3 rate select */
+	__be32	updrs3_l;	/* UTOPIA/POS device 3 rate select */
+	__be32	updrs4_h;	/* UTOPIA/POS device 4 rate select */
+	__be32	updrs4_l;	/* UTOPIA/POS device 4 rate select */
+	__be32	updrp1;		/* UTOPIA/POS device 1 receive priority low */
+	__be32	updrp2;		/* UTOPIA/POS device 2 receive priority low */
+	__be32	updrp3;		/* UTOPIA/POS device 3 receive priority low */
+	__be32	updrp4;		/* UTOPIA/POS device 4 receive priority low */
+	__be32	upde1;		/* UTOPIA/POS device 1 event */
+	__be32	upde2;		/* UTOPIA/POS device 2 event */
+	__be32	upde3;		/* UTOPIA/POS device 3 event */
+	__be32	upde4;		/* UTOPIA/POS device 4 event */
+	__be16	uprp1;
+	__be16	uprp2;
+	__be16	uprp3;
+	__be16	uprp4;
+	u8	res1[0x8];
+	__be16	uptirr1_0;	/* Device 1 transmit internal rate 0 */
+	__be16	uptirr1_1;	/* Device 1 transmit internal rate 1 */
+	__be16	uptirr1_2;	/* Device 1 transmit internal rate 2 */
+	__be16	uptirr1_3;	/* Device 1 transmit internal rate 3 */
+	__be16	uptirr2_0;	/* Device 2 transmit internal rate 0 */
+	__be16	uptirr2_1;	/* Device 2 transmit internal rate 1 */
+	__be16	uptirr2_2;	/* Device 2 transmit internal rate 2 */
+	__be16	uptirr2_3;	/* Device 2 transmit internal rate 3 */
+	__be16	uptirr3_0;	/* Device 3 transmit internal rate 0 */
+	__be16	uptirr3_1;	/* Device 3 transmit internal rate 1 */
+	__be16	uptirr3_2;	/* Device 3 transmit internal rate 2 */
+	__be16	uptirr3_3;	/* Device 3 transmit internal rate 3 */
+	__be16	uptirr4_0;	/* Device 4 transmit internal rate 0 */
+	__be16	uptirr4_1;	/* Device 4 transmit internal rate 1 */
+	__be16	uptirr4_2;	/* Device 4 transmit internal rate 2 */
+	__be16	uptirr4_3;	/* Device 4 transmit internal rate 3 */
+	__be32	uper1;		/* Device 1 port enable register */
+	__be32	uper2;		/* Device 2 port enable register */
+	__be32	uper3;		/* Device 3 port enable register */
+	__be32	uper4;		/* Device 4 port enable register */
+	u8	res2[0x150];
+} __attribute__ ((packed));
+
+/* SDMA */
+struct sdma {
+	__be32	sdsr;		/* Serial DMA status register */
+	__be32	sdmr;		/* Serial DMA mode register */
+	__be32	sdtr1;		/* SDMA system bus threshold register */
+	__be32	sdtr2;		/* SDMA secondary bus threshold register */
+	__be32	sdhy1;		/* SDMA system bus hysteresis register */
+	__be32	sdhy2;		/* SDMA secondary bus hysteresis register */
+	__be32	sdta1;		/* SDMA system bus address register */
+	__be32	sdta2;		/* SDMA secondary bus address register */
+	__be32	sdtm1;		/* SDMA system bus MSNUM register */
+	__be32	sdtm2;		/* SDMA secondary bus MSNUM register */
+	u8	res0[0x10];
+	__be32	sdaqr;		/* SDMA address bus qualify register */
+	__be32	sdaqmr;		/* SDMA address bus qualify mask register */
+	u8	res1[0x4];
+	__be32	sdebcr;		/* SDMA CAM entries base register */
+	u8	res2[0x38];
+} __attribute__ ((packed));
+
+/* Debug Space */
+struct dbg {
+	__be32	bpdcr;		/* Breakpoint debug command register */
+	__be32	bpdsr;		/* Breakpoint debug status register */
+	__be32	bpdmr;		/* Breakpoint debug mask register */
+	__be32	bprmrr0;	/* Breakpoint request mode risc register 0 */
+	__be32	bprmrr1;	/* Breakpoint request mode risc register 1 */
+	u8	res0[0x8];
+	__be32	bprmtr0;	/* Breakpoint request mode trb register 0 */
+	__be32	bprmtr1;	/* Breakpoint request mode trb register 1 */
+	u8	res1[0x8];
+	__be32	bprmir;		/* Breakpoint request mode immediate register */
+	__be32	bprmsr;		/* Breakpoint request mode serial register */
+	__be32	bpemr;		/* Breakpoint exit mode register */
+	u8	res2[0x48];
+} __attribute__ ((packed));
+
+/* RISC Special Registers (Trap and Breakpoint) */
+struct rsp {
+	u8	fixme[0x100];
+} __attribute__ ((packed));
+
+struct qe_immap {
+	struct qe_iram		iram;		/* I-RAM */
+	struct qe_ic_regs	ic;		/* Interrupt Controller */
+	struct cp_qe		cp;		/* Communications Processor */
+	struct qe_mux		qmx;		/* QE Multiplexer */
+	struct qe_timers	qet;		/* QE Timers */
+	struct spi		spi[0x2];	/* spi */
+	struct mcc		mcc;		/* mcc */
+	struct qe_brg		brg;		/* brg */
+	struct usb_ctlr		usb;		/* USB */
+	struct si1		si1;		/* SI */
+	u8			res11[0x800];
+	struct sir		sir;		/* SI Routing Tables */
+	struct ucc		ucc1;		/* ucc1 */
+	struct ucc		ucc3;		/* ucc3 */
+	struct ucc		ucc5;		/* ucc5 */
+	struct ucc		ucc7;		/* ucc7 */
+	u8			res12[0x600];
+	struct upc		upc1;		/* MultiPHY UTOPIA POS Ctrlr 1*/
+	struct ucc		ucc2;		/* ucc2 */
+	struct ucc		ucc4;		/* ucc4 */
+	struct ucc		ucc6;		/* ucc6 */
+	struct ucc		ucc8;		/* ucc8 */
+	u8			res13[0x600];
+	struct upc		upc2;		/* MultiPHY UTOPIA POS Ctrlr 2*/
+	struct sdma		sdma;		/* SDMA */
+	struct dbg		dbg;		/* Debug Space */
+	struct rsp		rsp[0x2];	/* RISC Special Registers
+						   (Trap and Breakpoint) */
+	u8			res14[0x300];
+	u8			res15[0x3A00];
+	u8			res16[0x8000];	/* 0x108000 - 0x110000 */
+	u8			muram[0xC000];	/* 0x110000 - 0x11C000
+						   Multi-user RAM */
+	u8			res17[0x24000];	/* 0x11C000 - 0x140000 */
+	u8			res18[0xC0000];	/* 0x140000 - 0x200000 */
+} __attribute__ ((packed));
+
+extern struct qe_immap *qe_immr;
+extern phys_addr_t get_qe_base(void);
+
+static inline unsigned long immrbar_virt_to_phys(volatile void * address)
+{
+	if ( ((u32)address >= (u32)qe_immr) &&
+			((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) )
+		return (unsigned long)(address - (u32)qe_immr +
+				(u32)get_qe_base());
+	return (unsigned long)virt_to_phys(address);
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_IMMAP_QE_H */
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 4da41ef..89ed545 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -9,7 +9,6 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/threads.h>
 #include <linux/list.h>
 #include <linux/radix-tree.h>
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 4f55573..86ee46b 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -6,7 +6,6 @@
 #include <asm-ppc/pci-bridge.h>
 #else
 
-#include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/list.h>
 
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
new file mode 100644
index 0000000..a62168ec
--- /dev/null
+++ b/include/asm-powerpc/qe.h
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * QUICC Engine (QE) external definitions and structure.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASM_POWERPC_QE_H
+#define _ASM_POWERPC_QE_H
+#ifdef __KERNEL__
+
+#include <asm/immap_qe.h>
+
+#define QE_NUM_OF_SNUM	28
+#define QE_NUM_OF_BRGS	16
+#define QE_NUM_OF_PORTS	1024
+
+/* Memory partitions
+*/
+#define MEM_PART_SYSTEM		0
+#define MEM_PART_SECONDARY	1
+#define MEM_PART_MURAM		2
+
+/* Export QE common operations */
+extern void qe_reset(void);
+extern int par_io_init(struct device_node *np);
+extern int par_io_of_config(struct device_node *np);
+
+/* QE internal API */
+int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input);
+void qe_setbrg(u32 brg, u32 rate);
+int qe_get_snum(void);
+void qe_put_snum(u8 snum);
+u32 qe_muram_alloc(u32 size, u32 align);
+int qe_muram_free(u32 offset);
+u32 qe_muram_alloc_fixed(u32 offset, u32 size);
+void qe_muram_dump(void);
+void *qe_muram_addr(u32 offset);
+
+/* Buffer descriptors */
+struct qe_bd {
+	u16 status;
+	u16 length;
+	u32 buf;
+} __attribute__ ((packed));
+
+#define BD_STATUS_MASK	0xffff0000
+#define BD_LENGTH_MASK	0x0000ffff
+
+/* Alignment */
+#define QE_INTR_TABLE_ALIGN	16	/* ??? */
+#define QE_ALIGNMENT_OF_BD	8
+#define QE_ALIGNMENT_OF_PRAM	64
+
+/* RISC allocation */
+enum qe_risc_allocation {
+	QE_RISC_ALLOCATION_RISC1 = 1,	/* RISC 1 */
+	QE_RISC_ALLOCATION_RISC2 = 2,	/* RISC 2 */
+	QE_RISC_ALLOCATION_RISC1_AND_RISC2 = 3	/* Dynamically choose
+						   RISC 1 or RISC 2 */
+};
+
+/* QE extended filtering Table Lookup Key Size */
+enum qe_fltr_tbl_lookup_key_size {
+	QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES
+		= 0x3f,		/* LookupKey parsed by the Generate LookupKey
+				   CMD is truncated to 8 bytes */
+	QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES
+		= 0x5f,		/* LookupKey parsed by the Generate LookupKey
+				   CMD is truncated to 16 bytes */
+};
+
+/* QE FLTR extended filtering Largest External Table Lookup Key Size */
+enum qe_fltr_largest_external_tbl_lookup_key_size {
+	QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE
+		= 0x0,/* not used */
+	QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES
+		= QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES,	/* 8 bytes */
+	QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES
+		= QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES,	/* 16 bytes */
+};
+
+/* structure representing QE parameter RAM */
+struct qe_timer_tables {
+	u16 tm_base;		/* QE timer table base adr */
+	u16 tm_ptr;		/* QE timer table pointer */
+	u16 r_tmr;		/* QE timer mode register */
+	u16 r_tmv;		/* QE timer valid register */
+	u32 tm_cmd;		/* QE timer cmd register */
+	u32 tm_cnt;		/* QE timer internal cnt */
+} __attribute__ ((packed));
+
+#define QE_FLTR_TAD_SIZE	8
+
+/* QE extended filtering Termination Action Descriptor (TAD) */
+struct qe_fltr_tad {
+	u8 serialized[QE_FLTR_TAD_SIZE];
+} __attribute__ ((packed));
+
+/* Communication Direction */
+enum comm_dir {
+	COMM_DIR_NONE = 0,
+	COMM_DIR_RX = 1,
+	COMM_DIR_TX = 2,
+	COMM_DIR_RX_AND_TX = 3
+};
+
+/* Clocks and BRGs */
+enum qe_clock {
+	QE_CLK_NONE = 0,
+	QE_BRG1,		/* Baud Rate Generator 1 */
+	QE_BRG2,		/* Baud Rate Generator 2 */
+	QE_BRG3,		/* Baud Rate Generator 3 */
+	QE_BRG4,		/* Baud Rate Generator 4 */
+	QE_BRG5,		/* Baud Rate Generator 5 */
+	QE_BRG6,		/* Baud Rate Generator 6 */
+	QE_BRG7,		/* Baud Rate Generator 7 */
+	QE_BRG8,		/* Baud Rate Generator 8 */
+	QE_BRG9,		/* Baud Rate Generator 9 */
+	QE_BRG10,		/* Baud Rate Generator 10 */
+	QE_BRG11,		/* Baud Rate Generator 11 */
+	QE_BRG12,		/* Baud Rate Generator 12 */
+	QE_BRG13,		/* Baud Rate Generator 13 */
+	QE_BRG14,		/* Baud Rate Generator 14 */
+	QE_BRG15,		/* Baud Rate Generator 15 */
+	QE_BRG16,		/* Baud Rate Generator 16 */
+	QE_CLK1,		/* Clock 1 */
+	QE_CLK2,		/* Clock 2 */
+	QE_CLK3,		/* Clock 3 */
+	QE_CLK4,		/* Clock 4 */
+	QE_CLK5,		/* Clock 5 */
+	QE_CLK6,		/* Clock 6 */
+	QE_CLK7,		/* Clock 7 */
+	QE_CLK8,		/* Clock 8 */
+	QE_CLK9,		/* Clock 9 */
+	QE_CLK10,		/* Clock 10 */
+	QE_CLK11,		/* Clock 11 */
+	QE_CLK12,		/* Clock 12 */
+	QE_CLK13,		/* Clock 13 */
+	QE_CLK14,		/* Clock 14 */
+	QE_CLK15,		/* Clock 15 */
+	QE_CLK16,		/* Clock 16 */
+	QE_CLK17,		/* Clock 17 */
+	QE_CLK18,		/* Clock 18 */
+	QE_CLK19,		/* Clock 19 */
+	QE_CLK20,		/* Clock 20 */
+	QE_CLK21,		/* Clock 21 */
+	QE_CLK22,		/* Clock 22 */
+	QE_CLK23,		/* Clock 23 */
+	QE_CLK24,		/* Clock 24 */
+	QE_CLK_DUMMY,
+};
+
+/* QE CMXUCR Registers.
+ * There are two UCCs represented in each of the four CMXUCR registers.
+ * These values are for the UCC in the LSBs
+ */
+#define QE_CMXUCR_MII_ENET_MNG		0x00007000
+#define QE_CMXUCR_MII_ENET_MNG_SHIFT	12
+#define QE_CMXUCR_GRANT			0x00008000
+#define QE_CMXUCR_TSA			0x00004000
+#define QE_CMXUCR_BKPT			0x00000100
+#define QE_CMXUCR_TX_CLK_SRC_MASK	0x0000000F
+
+/* QE CMXGCR Registers.
+*/
+#define QE_CMXGCR_MII_ENET_MNG		0x00007000
+#define QE_CMXGCR_MII_ENET_MNG_SHIFT	12
+#define QE_CMXGCR_USBCS			0x0000000f
+
+/* QE CECR Commands.
+*/
+#define QE_CR_FLG			0x00010000
+#define QE_RESET			0x80000000
+#define QE_INIT_TX_RX			0x00000000
+#define QE_INIT_RX			0x00000001
+#define QE_INIT_TX			0x00000002
+#define QE_ENTER_HUNT_MODE		0x00000003
+#define QE_STOP_TX			0x00000004
+#define QE_GRACEFUL_STOP_TX		0x00000005
+#define QE_RESTART_TX			0x00000006
+#define QE_CLOSE_RX_BD			0x00000007
+#define QE_SWITCH_COMMAND		0x00000007
+#define QE_SET_GROUP_ADDRESS		0x00000008
+#define QE_START_IDMA			0x00000009
+#define QE_MCC_STOP_RX			0x00000009
+#define QE_ATM_TRANSMIT			0x0000000a
+#define QE_HPAC_CLEAR_ALL		0x0000000b
+#define QE_GRACEFUL_STOP_RX		0x0000001a
+#define QE_RESTART_RX			0x0000001b
+#define QE_HPAC_SET_PRIORITY		0x0000010b
+#define QE_HPAC_STOP_TX			0x0000020b
+#define QE_HPAC_STOP_RX			0x0000030b
+#define QE_HPAC_GRACEFUL_STOP_TX	0x0000040b
+#define QE_HPAC_GRACEFUL_STOP_RX	0x0000050b
+#define QE_HPAC_START_TX		0x0000060b
+#define QE_HPAC_START_RX		0x0000070b
+#define QE_USB_STOP_TX			0x0000000a
+#define QE_USB_RESTART_TX		0x0000000b
+#define QE_QMC_STOP_TX			0x0000000c
+#define QE_QMC_STOP_RX			0x0000000d
+#define QE_SS7_SU_FIL_RESET		0x0000000e
+/* jonathbr added from here down for 83xx */
+#define QE_RESET_BCS			0x0000000a
+#define QE_MCC_INIT_TX_RX_16		0x00000003
+#define QE_MCC_STOP_TX			0x00000004
+#define QE_MCC_INIT_TX_1		0x00000005
+#define QE_MCC_INIT_RX_1		0x00000006
+#define QE_MCC_RESET			0x00000007
+#define QE_SET_TIMER			0x00000008
+#define QE_RANDOM_NUMBER		0x0000000c
+#define QE_ATM_MULTI_THREAD_INIT	0x00000011
+#define QE_ASSIGN_PAGE			0x00000012
+#define QE_ADD_REMOVE_HASH_ENTRY	0x00000013
+#define QE_START_FLOW_CONTROL		0x00000014
+#define QE_STOP_FLOW_CONTROL		0x00000015
+#define QE_ASSIGN_PAGE_TO_DEVICE	0x00000016
+
+#define QE_ASSIGN_RISC			0x00000010
+#define QE_CR_MCN_NORMAL_SHIFT		6
+#define QE_CR_MCN_USB_SHIFT		4
+#define QE_CR_MCN_RISC_ASSIGN_SHIFT	8
+#define QE_CR_SNUM_SHIFT		17
+
+/* QE CECR Sub Block - sub block of QE command.
+*/
+#define QE_CR_SUBBLOCK_INVALID		0x00000000
+#define QE_CR_SUBBLOCK_USB		0x03200000
+#define QE_CR_SUBBLOCK_UCCFAST1		0x02000000
+#define QE_CR_SUBBLOCK_UCCFAST2		0x02200000
+#define QE_CR_SUBBLOCK_UCCFAST3		0x02400000
+#define QE_CR_SUBBLOCK_UCCFAST4		0x02600000
+#define QE_CR_SUBBLOCK_UCCFAST5		0x02800000
+#define QE_CR_SUBBLOCK_UCCFAST6		0x02a00000
+#define QE_CR_SUBBLOCK_UCCFAST7		0x02c00000
+#define QE_CR_SUBBLOCK_UCCFAST8		0x02e00000
+#define QE_CR_SUBBLOCK_UCCSLOW1		0x00000000
+#define QE_CR_SUBBLOCK_UCCSLOW2		0x00200000
+#define QE_CR_SUBBLOCK_UCCSLOW3		0x00400000
+#define QE_CR_SUBBLOCK_UCCSLOW4		0x00600000
+#define QE_CR_SUBBLOCK_UCCSLOW5		0x00800000
+#define QE_CR_SUBBLOCK_UCCSLOW6		0x00a00000
+#define QE_CR_SUBBLOCK_UCCSLOW7		0x00c00000
+#define QE_CR_SUBBLOCK_UCCSLOW8		0x00e00000
+#define QE_CR_SUBBLOCK_MCC1		0x03800000
+#define QE_CR_SUBBLOCK_MCC2		0x03a00000
+#define QE_CR_SUBBLOCK_MCC3		0x03000000
+#define QE_CR_SUBBLOCK_IDMA1		0x02800000
+#define QE_CR_SUBBLOCK_IDMA2		0x02a00000
+#define QE_CR_SUBBLOCK_IDMA3		0x02c00000
+#define QE_CR_SUBBLOCK_IDMA4		0x02e00000
+#define QE_CR_SUBBLOCK_HPAC		0x01e00000
+#define QE_CR_SUBBLOCK_SPI1		0x01400000
+#define QE_CR_SUBBLOCK_SPI2		0x01600000
+#define QE_CR_SUBBLOCK_RAND		0x01c00000
+#define QE_CR_SUBBLOCK_TIMER		0x01e00000
+#define QE_CR_SUBBLOCK_GENERAL		0x03c00000
+
+/* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command */
+#define QE_CR_PROTOCOL_UNSPECIFIED	0x00	/* For all other protocols */
+#define QE_CR_PROTOCOL_HDLC_TRANSPARENT	0x00
+#define QE_CR_PROTOCOL_ATM_POS		0x0A
+#define QE_CR_PROTOCOL_ETHERNET		0x0C
+#define QE_CR_PROTOCOL_L2_SWITCH	0x0D
+
+/* BMR byte order */
+#define QE_BMR_BYTE_ORDER_BO_PPC	0x08	/* powerpc little endian */
+#define QE_BMR_BYTE_ORDER_BO_MOT	0x10	/* motorola big endian */
+#define QE_BMR_BYTE_ORDER_BO_MAX	0x18
+
+/* BRG configuration register */
+#define QE_BRGC_ENABLE		0x00010000
+#define QE_BRGC_DIVISOR_SHIFT	1
+#define QE_BRGC_DIVISOR_MAX	0xFFF
+#define QE_BRGC_DIV16		1
+
+/* QE Timers registers */
+#define QE_GTCFR1_PCAS	0x80
+#define QE_GTCFR1_STP2	0x20
+#define QE_GTCFR1_RST2	0x10
+#define QE_GTCFR1_GM2	0x08
+#define QE_GTCFR1_GM1	0x04
+#define QE_GTCFR1_STP1	0x02
+#define QE_GTCFR1_RST1	0x01
+
+/* SDMA registers */
+#define QE_SDSR_BER1	0x02000000
+#define QE_SDSR_BER2	0x01000000
+
+#define QE_SDMR_GLB_1_MSK	0x80000000
+#define QE_SDMR_ADR_SEL		0x20000000
+#define QE_SDMR_BER1_MSK	0x02000000
+#define QE_SDMR_BER2_MSK	0x01000000
+#define QE_SDMR_EB1_MSK		0x00800000
+#define QE_SDMR_ER1_MSK		0x00080000
+#define QE_SDMR_ER2_MSK		0x00040000
+#define QE_SDMR_CEN_MASK	0x0000E000
+#define QE_SDMR_SBER_1		0x00000200
+#define QE_SDMR_SBER_2		0x00000200
+#define QE_SDMR_EB1_PR_MASK	0x000000C0
+#define QE_SDMR_ER1_PR		0x00000008
+
+#define QE_SDMR_CEN_SHIFT	13
+#define QE_SDMR_EB1_PR_SHIFT	6
+
+#define QE_SDTM_MSNUM_SHIFT	24
+
+#define QE_SDEBCR_BA_MASK	0x01FFFFFF
+
+/* UPC */
+#define UPGCR_PROTOCOL	0x80000000	/* protocol ul2 or pl2 */
+#define UPGCR_TMS	0x40000000	/* Transmit master/slave mode */
+#define UPGCR_RMS	0x20000000	/* Receive master/slave mode */
+#define UPGCR_ADDR	0x10000000	/* Master MPHY Addr multiplexing */
+#define UPGCR_DIAG	0x01000000	/* Diagnostic mode */
+
+/* UCC */
+#define UCC_GUEMR_MODE_MASK_RX	0x02
+#define UCC_GUEMR_MODE_MASK_TX	0x01
+#define UCC_GUEMR_MODE_FAST_RX	0x02
+#define UCC_GUEMR_MODE_FAST_TX	0x01
+#define UCC_GUEMR_MODE_SLOW_RX	0x00
+#define UCC_GUEMR_MODE_SLOW_TX	0x00
+#define UCC_GUEMR_SET_RESERVED3	0x10	/* Bit 3 in the guemr is reserved but
+					   must be set 1 */
+
+/* structure representing UCC SLOW parameter RAM */
+struct ucc_slow_pram {
+	u16 rbase;		/* RX BD base address */
+	u16 tbase;		/* TX BD base address */
+	u8 rfcr;		/* Rx function code */
+	u8 tfcr;		/* Tx function code */
+	u16 mrblr;		/* Rx buffer length */
+	u32 rstate;		/* Rx internal state */
+	u32 rptr;		/* Rx internal data pointer */
+	u16 rbptr;		/* rb BD Pointer */
+	u16 rcount;		/* Rx internal byte count */
+	u32 rtemp;		/* Rx temp */
+	u32 tstate;		/* Tx internal state */
+	u32 tptr;		/* Tx internal data pointer */
+	u16 tbptr;		/* Tx BD pointer */
+	u16 tcount;		/* Tx byte count */
+	u32 ttemp;		/* Tx temp */
+	u32 rcrc;		/* temp receive CRC */
+	u32 tcrc;		/* temp transmit CRC */
+} __attribute__ ((packed));
+
+/* General UCC SLOW Mode Register (GUMRH & GUMRL) */
+#define UCC_SLOW_GUMR_H_CRC16		0x00004000
+#define UCC_SLOW_GUMR_H_CRC16CCITT	0x00000000
+#define UCC_SLOW_GUMR_H_CRC32CCITT	0x00008000
+#define UCC_SLOW_GUMR_H_REVD		0x00002000
+#define UCC_SLOW_GUMR_H_TRX		0x00001000
+#define UCC_SLOW_GUMR_H_TTX		0x00000800
+#define UCC_SLOW_GUMR_H_CDP		0x00000400
+#define UCC_SLOW_GUMR_H_CTSP		0x00000200
+#define UCC_SLOW_GUMR_H_CDS		0x00000100
+#define UCC_SLOW_GUMR_H_CTSS		0x00000080
+#define UCC_SLOW_GUMR_H_TFL		0x00000040
+#define UCC_SLOW_GUMR_H_RFW		0x00000020
+#define UCC_SLOW_GUMR_H_TXSY		0x00000010
+#define UCC_SLOW_GUMR_H_4SYNC		0x00000004
+#define UCC_SLOW_GUMR_H_8SYNC		0x00000008
+#define UCC_SLOW_GUMR_H_16SYNC		0x0000000c
+#define UCC_SLOW_GUMR_H_RTSM		0x00000002
+#define UCC_SLOW_GUMR_H_RSYN		0x00000001
+
+#define UCC_SLOW_GUMR_L_TCI		0x10000000
+#define UCC_SLOW_GUMR_L_RINV		0x02000000
+#define UCC_SLOW_GUMR_L_TINV		0x01000000
+#define UCC_SLOW_GUMR_L_TEND		0x00020000
+#define UCC_SLOW_GUMR_L_ENR		0x00000020
+#define UCC_SLOW_GUMR_L_ENT		0x00000010
+
+/* General UCC FAST Mode Register */
+#define UCC_FAST_GUMR_TCI	0x20000000
+#define UCC_FAST_GUMR_TRX	0x10000000
+#define UCC_FAST_GUMR_TTX	0x08000000
+#define UCC_FAST_GUMR_CDP	0x04000000
+#define UCC_FAST_GUMR_CTSP	0x02000000
+#define UCC_FAST_GUMR_CDS	0x01000000
+#define UCC_FAST_GUMR_CTSS	0x00800000
+#define UCC_FAST_GUMR_TXSY	0x00020000
+#define UCC_FAST_GUMR_RSYN	0x00010000
+#define UCC_FAST_GUMR_RTSM	0x00002000
+#define UCC_FAST_GUMR_REVD	0x00000400
+#define UCC_FAST_GUMR_ENR	0x00000020
+#define UCC_FAST_GUMR_ENT	0x00000010
+
+/* Slow UCC Event Register (UCCE) */
+#define UCC_SLOW_UCCE_GLR	0x1000
+#define UCC_SLOW_UCCE_GLT	0x0800
+#define UCC_SLOW_UCCE_DCC	0x0400
+#define UCC_SLOW_UCCE_FLG	0x0200
+#define UCC_SLOW_UCCE_AB	0x0200
+#define UCC_SLOW_UCCE_IDLE	0x0100
+#define UCC_SLOW_UCCE_GRA	0x0080
+#define UCC_SLOW_UCCE_TXE	0x0010
+#define UCC_SLOW_UCCE_RXF	0x0008
+#define UCC_SLOW_UCCE_CCR	0x0008
+#define UCC_SLOW_UCCE_RCH	0x0008
+#define UCC_SLOW_UCCE_BSY	0x0004
+#define UCC_SLOW_UCCE_TXB	0x0002
+#define UCC_SLOW_UCCE_TX	0x0002
+#define UCC_SLOW_UCCE_RX	0x0001
+#define UCC_SLOW_UCCE_GOV	0x0001
+#define UCC_SLOW_UCCE_GUN	0x0002
+#define UCC_SLOW_UCCE_GINT	0x0004
+#define UCC_SLOW_UCCE_IQOV	0x0008
+
+#define UCC_SLOW_UCCE_HDLC_SET	(UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+		UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF | \
+		UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_ENET_SET	(UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+		UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF)
+#define UCC_SLOW_UCCE_TRANS_SET	(UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+		UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \
+		UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_UART_SET	(UCC_SLOW_UCCE_BSY | UCC_SLOW_UCCE_GRA | \
+		UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \
+		UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_QMC_SET	(UCC_SLOW_UCCE_IQOV | UCC_SLOW_UCCE_GINT | \
+		UCC_SLOW_UCCE_GUN | UCC_SLOW_UCCE_GOV)
+
+#define UCC_SLOW_UCCE_OTHER	(UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+		UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | \
+		UCC_SLOW_UCCE_GLR)
+
+#define UCC_SLOW_INTR_TX	UCC_SLOW_UCCE_TXB
+#define UCC_SLOW_INTR_RX	(UCC_SLOW_UCCE_RXF | UCC_SLOW_UCCE_RX)
+#define UCC_SLOW_INTR		(UCC_SLOW_INTR_TX | UCC_SLOW_INTR_RX)
+
+/* UCC Transmit On Demand Register (UTODR) */
+#define UCC_SLOW_TOD	0x8000
+#define UCC_FAST_TOD	0x8000
+
+/* Function code masks */
+#define FC_GBL				0x20
+#define FC_DTB_LCL			0x02
+#define UCC_FAST_FUNCTION_CODE_GBL	0x20
+#define UCC_FAST_FUNCTION_CODE_DTB_LCL	0x02
+#define UCC_FAST_FUNCTION_CODE_BDB_LCL	0x01
+
+static inline long IS_MURAM_ERR(const u32 offset)
+{
+	return offset > (u32) - 1000L;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_QE_H */
diff --git a/include/asm-powerpc/qe_ic.h b/include/asm-powerpc/qe_ic.h
new file mode 100644
index 0000000..e386fb7
--- /dev/null
+++ b/include/asm-powerpc/qe_ic.h
@@ -0,0 +1,64 @@
+/*
+ * include/asm-powerpc/qe_ic.h
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * QE IC external definitions and structure.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef _ASM_POWERPC_QE_IC_H
+#define _ASM_POWERPC_QE_IC_H
+
+#include <linux/irq.h>
+
+#define NUM_OF_QE_IC_GROUPS	6
+
+/* Flags when we init the QE IC */
+#define QE_IC_SPREADMODE_GRP_W			0x00000001
+#define QE_IC_SPREADMODE_GRP_X			0x00000002
+#define QE_IC_SPREADMODE_GRP_Y			0x00000004
+#define QE_IC_SPREADMODE_GRP_Z			0x00000008
+#define QE_IC_SPREADMODE_GRP_RISCA		0x00000010
+#define QE_IC_SPREADMODE_GRP_RISCB		0x00000020
+
+#define QE_IC_LOW_SIGNAL			0x00000100
+#define QE_IC_HIGH_SIGNAL			0x00000200
+
+#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH	0x00001000
+#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH	0x00002000
+#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH	0x00004000
+#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH	0x00008000
+#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH	0x00010000
+#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH	0x00020000
+#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH	0x00040000
+#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH	0x00080000
+#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH	0x00100000
+#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH	0x00200000
+#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH	0x00400000
+#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH	0x00800000
+#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT		(12)
+
+/* QE interrupt sources groups */
+enum qe_ic_grp_id {
+	QE_IC_GRP_W = 0,	/* QE interrupt controller group W */
+	QE_IC_GRP_X,		/* QE interrupt controller group X */
+	QE_IC_GRP_Y,		/* QE interrupt controller group Y */
+	QE_IC_GRP_Z,		/* QE interrupt controller group Z */
+	QE_IC_GRP_RISCA,	/* QE interrupt controller RISC group A */
+	QE_IC_GRP_RISCB		/* QE interrupt controller RISC group B */
+};
+
+void qe_ic_init(struct device_node *node, unsigned int flags);
+void qe_ic_set_highest_priority(unsigned int virq, int high);
+int qe_ic_set_priority(unsigned int virq, unsigned int priority);
+int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
+
+#endif /* _ASM_POWERPC_QE_IC_H */
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 4b41dea..4362759 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -91,10 +91,6 @@
 DEBUGGER_BOILERPLATE(debugger_dabr_match)
 DEBUGGER_BOILERPLATE(debugger_fault_handler)
 
-#ifdef CONFIG_XMON
-extern void xmon_init(int enable);
-#endif
-
 #else
 static inline int debugger(struct pt_regs *regs) { return 0; }
 static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
diff --git a/include/asm-powerpc/ucc.h b/include/asm-powerpc/ucc.h
new file mode 100644
index 0000000..afe3076
--- /dev/null
+++ b/include/asm-powerpc/ucc.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * Internal header file for UCC unit routines.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __UCC_H__
+#define __UCC_H__
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#define STATISTICS
+
+#define UCC_MAX_NUM	8
+
+/* Slow or fast type for UCCs.
+*/
+enum ucc_speed_type {
+	UCC_SPEED_TYPE_FAST, UCC_SPEED_TYPE_SLOW
+};
+
+/* Initial UCCs Parameter RAM address relative to: MEM_MAP_BASE (IMMR).
+*/
+enum ucc_pram_initial_offset {
+	UCC_PRAM_OFFSET_UCC1 = 0x8400,
+	UCC_PRAM_OFFSET_UCC2 = 0x8500,
+	UCC_PRAM_OFFSET_UCC3 = 0x8600,
+	UCC_PRAM_OFFSET_UCC4 = 0x9000,
+	UCC_PRAM_OFFSET_UCC5 = 0x8000,
+	UCC_PRAM_OFFSET_UCC6 = 0x8100,
+	UCC_PRAM_OFFSET_UCC7 = 0x8200,
+	UCC_PRAM_OFFSET_UCC8 = 0x8300
+};
+
+/* ucc_set_type
+ * Sets UCC to slow or fast mode.
+ *
+ * ucc_num - (In) number of UCC (0-7).
+ * regs    - (In) pointer to registers base for the UCC.
+ * speed   - (In) slow or fast mode for UCC.
+ */
+int ucc_set_type(int ucc_num, struct ucc_common *regs,
+		 enum ucc_speed_type speed);
+
+/* ucc_init_guemr
+ * Init the Guemr register.
+ *
+ * regs - (In) pointer to registers base for the UCC.
+ */
+int ucc_init_guemr(struct ucc_common *regs);
+
+int ucc_set_qe_mux_mii_mng(int ucc_num);
+
+int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode);
+
+int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask);
+
+/* QE MUX clock routing for UCC
+*/
+static inline int ucc_set_qe_mux_grant(int ucc_num, int set)
+{
+	return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_GRANT);
+}
+
+static inline int ucc_set_qe_mux_tsa(int ucc_num, int set)
+{
+	return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_TSA);
+}
+
+static inline int ucc_set_qe_mux_bkpt(int ucc_num, int set)
+{
+	return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_BKPT);
+}
+
+#endif				/* __UCC_H__ */
diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h
new file mode 100644
index 0000000..39d1c90
--- /dev/null
+++ b/include/asm-powerpc/ucc_fast.h
@@ -0,0 +1,243 @@
+/*
+ * include/asm-powerpc/ucc_fast.h
+ *
+ * Internal header file for UCC FAST unit routines.
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __UCC_FAST_H__
+#define __UCC_FAST_H__
+
+#include <linux/kernel.h>
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include "ucc.h"
+
+/* Receive BD's status */
+#define R_E	0x80000000	/* buffer empty */
+#define R_W	0x20000000	/* wrap bit */
+#define R_I	0x10000000	/* interrupt on reception */
+#define R_L	0x08000000	/* last */
+#define R_F	0x04000000	/* first */
+
+/* transmit BD's status */
+#define T_R	0x80000000	/* ready bit */
+#define T_W	0x20000000	/* wrap bit */
+#define T_I	0x10000000	/* interrupt on completion */
+#define T_L	0x08000000	/* last */
+
+/* Rx Data buffer must be 4 bytes aligned in most cases */
+#define UCC_FAST_RX_ALIGN			4
+#define UCC_FAST_MRBLR_ALIGNMENT		4
+#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT	8
+
+/* Sizes */
+#define UCC_FAST_URFS_MIN_VAL				0x88
+#define UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR	8
+
+/* ucc_fast_channel_protocol_mode - UCC FAST mode */
+enum ucc_fast_channel_protocol_mode {
+	UCC_FAST_PROTOCOL_MODE_HDLC = 0x00000000,
+	UCC_FAST_PROTOCOL_MODE_RESERVED01 = 0x00000001,
+	UCC_FAST_PROTOCOL_MODE_RESERVED_QMC = 0x00000002,
+	UCC_FAST_PROTOCOL_MODE_RESERVED02 = 0x00000003,
+	UCC_FAST_PROTOCOL_MODE_RESERVED_UART = 0x00000004,
+	UCC_FAST_PROTOCOL_MODE_RESERVED03 = 0x00000005,
+	UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_1 = 0x00000006,
+	UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_2 = 0x00000007,
+	UCC_FAST_PROTOCOL_MODE_RESERVED_BISYNC = 0x00000008,
+	UCC_FAST_PROTOCOL_MODE_RESERVED04 = 0x00000009,
+	UCC_FAST_PROTOCOL_MODE_ATM = 0x0000000A,
+	UCC_FAST_PROTOCOL_MODE_RESERVED05 = 0x0000000B,
+	UCC_FAST_PROTOCOL_MODE_ETHERNET = 0x0000000C,
+	UCC_FAST_PROTOCOL_MODE_RESERVED06 = 0x0000000D,
+	UCC_FAST_PROTOCOL_MODE_POS = 0x0000000E,
+	UCC_FAST_PROTOCOL_MODE_RESERVED07 = 0x0000000F
+};
+
+/* ucc_fast_transparent_txrx - UCC Fast Transparent TX & RX */
+enum ucc_fast_transparent_txrx {
+	UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL = 0x00000000,
+	UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_TRANSPARENT = 0x18000000
+};
+
+/* UCC fast diagnostic mode */
+enum ucc_fast_diag_mode {
+	UCC_FAST_DIAGNOSTIC_NORMAL = 0x0,
+	UCC_FAST_DIAGNOSTIC_LOCAL_LOOP_BACK = 0x40000000,
+	UCC_FAST_DIAGNOSTIC_AUTO_ECHO = 0x80000000,
+	UCC_FAST_DIAGNOSTIC_LOOP_BACK_AND_ECHO = 0xC0000000
+};
+
+/* UCC fast Sync length (transparent mode only) */
+enum ucc_fast_sync_len {
+	UCC_FAST_SYNC_LEN_NOT_USED = 0x0,
+	UCC_FAST_SYNC_LEN_AUTOMATIC = 0x00004000,
+	UCC_FAST_SYNC_LEN_8_BIT = 0x00008000,
+	UCC_FAST_SYNC_LEN_16_BIT = 0x0000C000
+};
+
+/* UCC fast RTS mode */
+enum ucc_fast_ready_to_send {
+	UCC_FAST_SEND_IDLES_BETWEEN_FRAMES = 0x00000000,
+	UCC_FAST_SEND_FLAGS_BETWEEN_FRAMES = 0x00002000
+};
+
+/* UCC fast receiver decoding mode */
+enum ucc_fast_rx_decoding_method {
+	UCC_FAST_RX_ENCODING_NRZ = 0x00000000,
+	UCC_FAST_RX_ENCODING_NRZI = 0x00000800,
+	UCC_FAST_RX_ENCODING_RESERVED0 = 0x00001000,
+	UCC_FAST_RX_ENCODING_RESERVED1 = 0x00001800
+};
+
+/* UCC fast transmitter encoding mode */
+enum ucc_fast_tx_encoding_method {
+	UCC_FAST_TX_ENCODING_NRZ = 0x00000000,
+	UCC_FAST_TX_ENCODING_NRZI = 0x00000100,
+	UCC_FAST_TX_ENCODING_RESERVED0 = 0x00000200,
+	UCC_FAST_TX_ENCODING_RESERVED1 = 0x00000300
+};
+
+/* UCC fast CRC length */
+enum ucc_fast_transparent_tcrc {
+	UCC_FAST_16_BIT_CRC = 0x00000000,
+	UCC_FAST_CRC_RESERVED0 = 0x00000040,
+	UCC_FAST_32_BIT_CRC = 0x00000080,
+	UCC_FAST_CRC_RESERVED1 = 0x000000C0
+};
+
+/* Fast UCC initialization structure */
+struct ucc_fast_info {
+	int ucc_num;
+	enum qe_clock rx_clock;
+	enum qe_clock tx_clock;
+	u32 regs;
+	int irq;
+	u32 uccm_mask;
+	int bd_mem_part;
+	int brkpt_support;
+	int grant_support;
+	int tsa;
+	int cdp;
+	int cds;
+	int ctsp;
+	int ctss;
+	int tci;
+	int txsy;
+	int rtsm;
+	int revd;
+	int rsyn;
+	u16 max_rx_buf_length;
+	u16 urfs;
+	u16 urfet;
+	u16 urfset;
+	u16 utfs;
+	u16 utfet;
+	u16 utftt;
+	u16 ufpt;
+	enum ucc_fast_channel_protocol_mode mode;
+	enum ucc_fast_transparent_txrx ttx_trx;
+	enum ucc_fast_tx_encoding_method tenc;
+	enum ucc_fast_rx_decoding_method renc;
+	enum ucc_fast_transparent_tcrc tcrc;
+	enum ucc_fast_sync_len synl;
+};
+
+struct ucc_fast_private {
+	struct ucc_fast_info *uf_info;
+	struct ucc_fast *uf_regs;	/* a pointer to memory map of UCC regs. */
+	u32 *p_ucce;		/* a pointer to the event register in memory. */
+	u32 *p_uccm;		/* a pointer to the mask register in memory. */
+	int enabled_tx;		/* Whether channel is enabled for Tx (ENT) */
+	int enabled_rx;		/* Whether channel is enabled for Rx (ENR) */
+	int stopped_tx;		/* Whether channel has been stopped for Tx
+				   (STOP_TX, etc.) */
+	int stopped_rx;		/* Whether channel has been stopped for Rx */
+	u32 ucc_fast_tx_virtual_fifo_base_offset;/* pointer to base of Tx
+						    virtual fifo */
+	u32 ucc_fast_rx_virtual_fifo_base_offset;/* pointer to base of Rx
+						    virtual fifo */
+#ifdef STATISTICS
+	u32 tx_frames;		/* Transmitted frames counter. */
+	u32 rx_frames;		/* Received frames counter (only frames
+				   passed to application). */
+	u32 tx_discarded;	/* Discarded tx frames counter (frames that
+				   were discarded by the driver due to errors).
+				   */
+	u32 rx_discarded;	/* Discarded rx frames counter (frames that
+				   were discarded by the driver due to errors).
+				   */
+#endif				/* STATISTICS */
+	u16 mrblr;		/* maximum receive buffer length */
+};
+
+/* ucc_fast_init
+ * Initializes Fast UCC according to user provided parameters.
+ *
+ * uf_info  - (In) pointer to the fast UCC info structure.
+ * uccf_ret - (Out) pointer to the fast UCC structure.
+ */
+int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret);
+
+/* ucc_fast_free
+ * Frees all resources for fast UCC.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_free(struct ucc_fast_private * uccf);
+
+/* ucc_fast_enable
+ * Enables a fast UCC port.
+ * This routine enables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode);
+
+/* ucc_fast_disable
+ * Disables a fast UCC port.
+ * This routine disables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode);
+
+/* ucc_fast_irq
+ * Handles interrupts on fast UCC.
+ * Called from the general interrupt routine to handle interrupts on fast UCC.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_irq(struct ucc_fast_private * uccf);
+
+/* ucc_fast_transmit_on_demand
+ * Immediately forces a poll of the transmitter for data to be sent.
+ * Typically, the hardware performs a periodic poll for data that the
+ * transmit routine has set up to be transmitted. In cases where
+ * this polling cycle is not soon enough, this optional routine can
+ * be invoked to force a poll right away, instead. Proper use for
+ * each transmission for which this functionality is desired is to
+ * call the transmit routine and then this routine right after.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf);
+
+u32 ucc_fast_get_qe_cr_subblock(int uccf_num);
+
+void ucc_fast_dump_regs(struct ucc_fast_private * uccf);
+
+#endif				/* __UCC_FAST_H__ */
diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h
new file mode 100644
index 0000000..ca93bc9
--- /dev/null
+++ b/include/asm-powerpc/ucc_slow.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: 	Shlomi Gridish <gridish@freescale.com>
+ * 		Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * Internal header file for UCC SLOW unit routines.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+#ifndef __UCC_SLOW_H__
+#define __UCC_SLOW_H__
+
+#include <linux/kernel.h>
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include "ucc.h"
+
+/* transmit BD's status */
+#define T_R	0x80000000	/* ready bit */
+#define T_PAD	0x40000000	/* add pads to short frames */
+#define T_W	0x20000000	/* wrap bit */
+#define T_I	0x10000000	/* interrupt on completion */
+#define T_L	0x08000000	/* last */
+
+#define T_A	0x04000000	/* Address - the data transmitted as address
+				   chars */
+#define T_TC	0x04000000	/* transmit CRC */
+#define T_CM	0x02000000	/* continuous mode */
+#define T_DEF	0x02000000	/* collision on previous attempt to transmit */
+#define T_P	0x01000000	/* Preamble - send Preamble sequence before
+				   data */
+#define T_HB	0x01000000	/* heartbeat */
+#define T_NS	0x00800000	/* No Stop */
+#define T_LC	0x00800000	/* late collision */
+#define T_RL	0x00400000	/* retransmission limit */
+#define T_UN	0x00020000	/* underrun */
+#define T_CT	0x00010000	/* CTS lost */
+#define T_CSL	0x00010000	/* carrier sense lost */
+#define T_RC	0x003c0000	/* retry count */
+
+/* Receive BD's status */
+#define R_E	0x80000000	/* buffer empty */
+#define R_W	0x20000000	/* wrap bit */
+#define R_I	0x10000000	/* interrupt on reception */
+#define R_L	0x08000000	/* last */
+#define R_C	0x08000000	/* the last byte in this buffer is a cntl
+				   char */
+#define R_F	0x04000000	/* first */
+#define R_A	0x04000000	/* the first byte in this buffer is address
+				   byte */
+#define R_CM	0x02000000	/* continuous mode */
+#define R_ID	0x01000000	/* buffer close on reception of idles */
+#define R_M	0x01000000	/* Frame received because of promiscuous
+				   mode */
+#define R_AM	0x00800000	/* Address match */
+#define R_DE	0x00800000	/* Address match */
+#define R_LG	0x00200000	/* Break received */
+#define R_BR	0x00200000	/* Frame length violation */
+#define R_NO	0x00100000	/* Rx Non Octet Aligned Packet */
+#define R_FR	0x00100000	/* Framing Error (no stop bit) character
+				   received */
+#define R_PR	0x00080000	/* Parity Error character received */
+#define R_AB	0x00080000	/* Frame Aborted */
+#define R_SH	0x00080000	/* frame is too short */
+#define R_CR	0x00040000	/* CRC Error */
+#define R_OV	0x00020000	/* Overrun */
+#define R_CD	0x00010000	/* CD lost */
+#define R_CL	0x00010000	/* this frame is closed because of a
+				   collision */
+
+/* Rx Data buffer must be 4 bytes aligned in most cases.*/
+#define UCC_SLOW_RX_ALIGN		4
+#define UCC_SLOW_MRBLR_ALIGNMENT	4
+#define UCC_SLOW_PRAM_SIZE		0x100
+#define ALIGNMENT_OF_UCC_SLOW_PRAM	64
+
+/* UCC Slow Channel Protocol Mode */
+enum ucc_slow_channel_protocol_mode {
+	UCC_SLOW_CHANNEL_PROTOCOL_MODE_QMC = 0x00000002,
+	UCC_SLOW_CHANNEL_PROTOCOL_MODE_UART = 0x00000004,
+	UCC_SLOW_CHANNEL_PROTOCOL_MODE_BISYNC = 0x00000008,
+};
+
+/* UCC Slow Transparent Transmit CRC (TCRC) */
+enum ucc_slow_transparent_tcrc {
+	/* 16-bit CCITT CRC (HDLC).  (X16 + X12 + X5 + 1) */
+	UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC16 = 0x00000000,
+	/* CRC16 (BISYNC).  (X16 + X15 + X2 + 1) */
+	UCC_SLOW_TRANSPARENT_TCRC_CRC16 = 0x00004000,
+	/* 32-bit CCITT CRC (Ethernet and HDLC) */
+	UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC32 = 0x00008000,
+};
+
+/* UCC Slow oversampling rate for transmitter (TDCR) */
+enum ucc_slow_tx_oversampling_rate {
+	/* 1x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_1 = 0x00000000,
+	/* 8x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_8 = 0x00010000,
+	/* 16x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_16 = 0x00020000,
+	/* 32x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_32 = 0x00030000,
+};
+
+/* UCC Slow Oversampling rate for receiver (RDCR)
+*/
+enum ucc_slow_rx_oversampling_rate {
+	/* 1x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_1 = 0x00000000,
+	/* 8x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_8 = 0x00004000,
+	/* 16x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_16 = 0x00008000,
+	/* 32x clock mode */
+	UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_32 = 0x0000c000,
+};
+
+/* UCC Slow Transmitter encoding method (TENC)
+*/
+enum ucc_slow_tx_encoding_method {
+	UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZ = 0x00000000,
+	UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZI = 0x00000100
+};
+
+/* UCC Slow Receiver decoding method (RENC)
+*/
+enum ucc_slow_rx_decoding_method {
+	UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZ = 0x00000000,
+	UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZI = 0x00000800
+};
+
+/* UCC Slow Diagnostic mode (DIAG)
+*/
+enum ucc_slow_diag_mode {
+	UCC_SLOW_DIAG_MODE_NORMAL = 0x00000000,
+	UCC_SLOW_DIAG_MODE_LOOPBACK = 0x00000040,
+	UCC_SLOW_DIAG_MODE_ECHO = 0x00000080,
+	UCC_SLOW_DIAG_MODE_LOOPBACK_ECHO = 0x000000c0
+};
+
+struct ucc_slow_info {
+	int ucc_num;
+	enum qe_clock rx_clock;
+	enum qe_clock tx_clock;
+	struct ucc_slow *us_regs;
+	int irq;
+	u16 uccm_mask;
+	int data_mem_part;
+	int init_tx;
+	int init_rx;
+	u32 tx_bd_ring_len;
+	u32 rx_bd_ring_len;
+	int rx_interrupts;
+	int brkpt_support;
+	int grant_support;
+	int tsa;
+	int cdp;
+	int cds;
+	int ctsp;
+	int ctss;
+	int rinv;
+	int tinv;
+	int rtsm;
+	int rfw;
+	int tci;
+	int tend;
+	int tfl;
+	int txsy;
+	u16 max_rx_buf_length;
+	enum ucc_slow_transparent_tcrc tcrc;
+	enum ucc_slow_channel_protocol_mode mode;
+	enum ucc_slow_diag_mode diag;
+	enum ucc_slow_tx_oversampling_rate tdcr;
+	enum ucc_slow_rx_oversampling_rate rdcr;
+	enum ucc_slow_tx_encoding_method tenc;
+	enum ucc_slow_rx_decoding_method renc;
+};
+
+struct ucc_slow_private {
+	struct ucc_slow_info *us_info;
+	struct ucc_slow *us_regs;	/* a pointer to memory map of UCC regs */
+	struct ucc_slow_pram *us_pram;	/* a pointer to the parameter RAM */
+	u32 us_pram_offset;
+	int enabled_tx;		/* Whether channel is enabled for Tx (ENT) */
+	int enabled_rx;		/* Whether channel is enabled for Rx (ENR) */
+	int stopped_tx;		/* Whether channel has been stopped for Tx
+				   (STOP_TX, etc.) */
+	int stopped_rx;		/* Whether channel has been stopped for Rx */
+	struct list_head confQ;	/* frames passed to chip waiting for tx */
+	u32 first_tx_bd_mask;	/* mask is used in Tx routine to save status
+				   and length for first BD in a frame */
+	u32 tx_base_offset;	/* first BD in Tx BD table offset (In MURAM) */
+	u32 rx_base_offset;	/* first BD in Rx BD table offset (In MURAM) */
+	u8 *confBd;		/* next BD for confirm after Tx */
+	u8 *tx_bd;		/* next BD for new Tx request */
+	u8 *rx_bd;		/* next BD to collect after Rx */
+	void *p_rx_frame;	/* accumulating receive frame */
+	u16 *p_ucce;		/* a pointer to the event register in memory.
+				 */
+	u16 *p_uccm;		/* a pointer to the mask register in memory */
+	u16 saved_uccm;		/* a saved mask for the RX Interrupt bits */
+#ifdef STATISTICS
+	u32 tx_frames;		/* Transmitted frames counters */
+	u32 rx_frames;		/* Received frames counters (only frames
+				   passed to application) */
+	u32 rx_discarded;	/* Discarded frames counters (frames that
+				   were discarded by the driver due to
+				   errors) */
+#endif				/* STATISTICS */
+};
+
+/* ucc_slow_init
+ * Initializes Slow UCC according to provided parameters.
+ *
+ * us_info  - (In) pointer to the slow UCC info structure.
+ * uccs_ret - (Out) pointer to the slow UCC structure.
+ */
+int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret);
+
+/* ucc_slow_free
+ * Frees all resources for slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_free(struct ucc_slow_private * uccs);
+
+/* ucc_slow_enable
+ * Enables a fast UCC port.
+ * This routine enables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode);
+
+/* ucc_slow_disable
+ * Disables a fast UCC port.
+ * This routine disables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode);
+
+/* ucc_slow_poll_transmitter_now
+ * Immediately forces a poll of the transmitter for data to be sent.
+ * Typically, the hardware performs a periodic poll for data that the
+ * transmit routine has set up to be transmitted. In cases where
+ * this polling cycle is not soon enough, this optional routine can
+ * be invoked to force a poll right away, instead. Proper use for
+ * each transmission for which this functionality is desired is to
+ * call the transmit routine and then this routine right after.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs);
+
+/* ucc_slow_graceful_stop_tx
+ * Smoothly stops transmission on a specified slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs);
+
+/* ucc_slow_stop_tx
+ * Stops transmission on a specified slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_stop_tx(struct ucc_slow_private * uccs);
+
+/* ucc_slow_restart_x
+ * Restarts transmitting on a specified slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_restart_x(struct ucc_slow_private * uccs);
+
+u32 ucc_slow_get_qe_cr_subblock(int uccs_num);
+
+#endif				/* __UCC_SLOW_H__ */
diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h
index 43f7129..f1d337e 100644
--- a/include/asm-powerpc/xmon.h
+++ b/include/asm-powerpc/xmon.h
@@ -1,12 +1,22 @@
-#ifndef __PPC_XMON_H
-#define __PPC_XMON_H
+#ifndef __ASM_POWERPC_XMON_H
+#define __ASM_POWERPC_XMON_H
+
+/*
+ * Copyrignt (C) 2006 IBM Corp
+ *
+ * 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.
+ */
+
 #ifdef __KERNEL__
 
-struct pt_regs;
-
-extern int xmon(struct pt_regs *excp);
-extern void xmon_printf(const char *fmt, ...);
-extern void xmon_init(int);
-
+#ifdef CONFIG_XMON
+extern void xmon_setup(void);
+#else
+static inline void xmon_setup(void) { };
 #endif
-#endif
+
+#endif /* __KERNEL __ */
+#endif /* __ASM_POWERPC_XMON_H */
diff --git a/include/asm-sparc64/compat_signal.h b/include/asm-sparc64/compat_signal.h
index 7aefa30..b759eab 100644
--- a/include/asm-sparc64/compat_signal.h
+++ b/include/asm-sparc64/compat_signal.h
@@ -1,7 +1,6 @@
 #ifndef _COMPAT_SIGNAL_H
 #define _COMPAT_SIGNAL_H
 
-#include <linux/config.h>
 #include <linux/compat.h>
 #include <asm/signal.h>
 
diff --git a/include/asm-x86_64/alternative-asm.i b/include/asm-x86_64/alternative-asm.i
index e4041f4..0b3f1a2 100644
--- a/include/asm-x86_64/alternative-asm.i
+++ b/include/asm-x86_64/alternative-asm.i
@@ -1,5 +1,3 @@
-#include <linux/config.h>
-
 #ifdef CONFIG_SMP
 	.macro LOCK_PREFIX
 1:	lock
diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
index 64a65ce..95d5e09 100644
--- a/include/asm-x86_64/hardirq.h
+++ b/include/asm-x86_64/hardirq.h
@@ -6,6 +6,9 @@
 #include <asm/pda.h>
 #include <asm/apic.h>
 
+/* We can have at most NR_VECTORS irqs routed to a cpu at a time */
+#define MAX_HARDIRQS_PER_CPU NR_VECTORS
+
 #define __ARCH_IRQ_STAT 1
 
 #define local_softirq_pending() read_pda(__softirq_pending)
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index 48a4a53..53d0d9f 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -19,8 +19,7 @@
 #include <asm/irq.h>
 #include <linux/profile.h>
 #include <linux/smp.h>
-
-struct hw_interrupt_type;
+#include <linux/percpu.h>
 #endif
 
 #define NMI_VECTOR		0x02
@@ -75,9 +74,10 @@
 
 
 #ifndef __ASSEMBLY__
-extern u8 irq_vector[NR_IRQ_VECTORS];
+extern unsigned int irq_vector[NR_IRQ_VECTORS];
+typedef int vector_irq_t[NR_VECTORS];
+DECLARE_PER_CPU(vector_irq_t, vector_irq);
 #define IO_APIC_VECTOR(irq)	(irq_vector[irq])
-#define AUTO_ASSIGN		-1
 
 /*
  * Various low-level irq details needed by irq.c, process.c,
diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h
new file mode 100644
index 0000000..c16c6ff
--- /dev/null
+++ b/include/asm-x86_64/hypertransport.h
@@ -0,0 +1,42 @@
+#ifndef ASM_HYPERTRANSPORT_H
+#define ASM_HYPERTRANSPORT_H
+
+/*
+ * Constants for x86 Hypertransport Interrupts.
+ */
+
+#define HT_IRQ_LOW_BASE			0xf8000000
+
+#define HT_IRQ_LOW_VECTOR_SHIFT		16
+#define  HT_IRQ_LOW_VECTOR_MASK		0x00ff0000
+#define  HT_IRQ_LOW_VECTOR(v)		(((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
+
+#define HT_IRQ_LOW_DEST_ID_SHIFT	8
+#define  HT_IRQ_LOW_DEST_ID_MASK	0x0000ff00
+#define  HT_IRQ_LOW_DEST_ID(v)		(((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
+
+#define HT_IRQ_LOW_DM_PHYSICAL		0x0000000
+#define HT_IRQ_LOW_DM_LOGICAL		0x0000040
+
+#define HT_IRQ_LOW_RQEOI_EDGE		0x0000000
+#define HT_IRQ_LOW_RQEOI_LEVEL		0x0000020
+
+
+#define HT_IRQ_LOW_MT_FIXED		0x0000000
+#define HT_IRQ_LOW_MT_ARBITRATED	0x0000004
+#define HT_IRQ_LOW_MT_SMI		0x0000008
+#define HT_IRQ_LOW_MT_NMI		0x000000c
+#define HT_IRQ_LOW_MT_INIT		0x0000010
+#define HT_IRQ_LOW_MT_STARTUP		0x0000014
+#define HT_IRQ_LOW_MT_EXTINT		0x0000018
+#define HT_IRQ_LOW_MT_LINT1		0x000008c
+#define HT_IRQ_LOW_MT_LINT0		0x0000098
+
+#define HT_IRQ_LOW_IRQ_MASKED		0x0000001
+
+
+#define HT_IRQ_HIGH_DEST_ID_SHIFT	0
+#define  HT_IRQ_HIGH_DEST_ID_MASK	0x00ffffff
+#define  HT_IRQ_HIGH_DEST_ID(v)		((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
+
+#endif /* ASM_HYPERTRANSPORT_H */
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
index 5d1b5c6..171ec2d 100644
--- a/include/asm-x86_64/io_apic.h
+++ b/include/asm-x86_64/io_apic.h
@@ -10,46 +10,6 @@
  * Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
  */
 
-#ifdef CONFIG_PCI_MSI
-static inline int use_pci_vector(void)	{return 1;}
-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
-static inline void end_edge_ioapic_vector (unsigned int vector) { }
-#define startup_level_ioapic	startup_level_ioapic_vector
-#define shutdown_level_ioapic	mask_IO_APIC_vector
-#define enable_level_ioapic	unmask_IO_APIC_vector
-#define disable_level_ioapic	mask_IO_APIC_vector
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
-#define end_level_ioapic	end_level_ioapic_vector
-#define set_ioapic_affinity	set_ioapic_affinity_vector
-
-#define startup_edge_ioapic 	startup_edge_ioapic_vector
-#define shutdown_edge_ioapic 	disable_edge_ioapic_vector
-#define enable_edge_ioapic 	unmask_IO_APIC_vector
-#define disable_edge_ioapic 	disable_edge_ioapic_vector
-#define ack_edge_ioapic 	ack_edge_ioapic_vector
-#define end_edge_ioapic 	end_edge_ioapic_vector
-#else
-static inline int use_pci_vector(void)	{return 0;}
-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
-static inline void end_edge_ioapic_irq (unsigned int irq) { }
-#define startup_level_ioapic	startup_level_ioapic_irq
-#define shutdown_level_ioapic	mask_IO_APIC_irq
-#define enable_level_ioapic	unmask_IO_APIC_irq
-#define disable_level_ioapic	mask_IO_APIC_irq
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
-#define end_level_ioapic	end_level_ioapic_irq
-#define set_ioapic_affinity	set_ioapic_affinity_irq
-
-#define startup_edge_ioapic 	startup_edge_ioapic_irq
-#define shutdown_edge_ioapic 	disable_edge_ioapic_irq
-#define enable_edge_ioapic 	unmask_IO_APIC_irq
-#define disable_edge_ioapic 	disable_edge_ioapic_irq
-#define ack_edge_ioapic 	ack_edge_ioapic_irq
-#define end_edge_ioapic 	end_edge_ioapic_irq
-#endif
-
 #define APIC_MISMATCH_DEBUG
 
 #define IO_APIC_BASE(idx) \
@@ -202,13 +162,10 @@
 extern int io_apic_get_version (int ioapic);
 extern int io_apic_get_redir_entries (int ioapic);
 extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int);
-extern int timer_uses_ioapic_pin_0;
 #endif
 
 extern int sis_apic_bug; /* dummy */ 
 
-extern int assign_irq_vector(int irq);
-
 void enable_NMI_through_LVT0 (void * dummy);
 
 extern spinlock_t i8259A_lock;
diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h
index 43469d8a..5006c6e 100644
--- a/include/asm-x86_64/irq.h
+++ b/include/asm-x86_64/irq.h
@@ -31,13 +31,8 @@
 
 #define FIRST_SYSTEM_VECTOR	0xef   /* duplicated in hw_irq.h */
 
-#ifdef CONFIG_PCI_MSI
-#define NR_IRQS FIRST_SYSTEM_VECTOR
+#define NR_IRQS (NR_VECTORS + (32 *NR_CPUS))
 #define NR_IRQ_VECTORS NR_IRQS
-#else
-#define NR_IRQS 224
-#define NR_IRQ_VECTORS (32 * NR_CPUS)
-#endif
 
 static __inline__ int irq_canonicalize(int irq)
 {
diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h
deleted file mode 100644
index 3ad23466..0000000
--- a/include/asm-x86_64/msi.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <asm/mach_apic.h>
-#include <asm/smp.h>
-
-#define LAST_DEVICE_VECTOR	(FIRST_SYSTEM_VECTOR - 1)
-#define MSI_TARGET_CPU_SHIFT	12
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
-	msi_register(&msi_apic_ops);
-	return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h
new file mode 100644
index 0000000..5b8acdd
--- /dev/null
+++ b/include/asm-x86_64/msidef.h
@@ -0,0 +1,47 @@
+#ifndef ASM_MSIDEF_H
+#define ASM_MSIDEF_H
+
+/*
+ * Constants for Intel APIC based MSI messages.
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT		0
+#define  MSI_DATA_VECTOR_MASK		0x000000ff
+#define	 MSI_DATA_VECTOR(v)		(((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT	8
+#define  MSI_DATA_DELIVERY_FIXED	(0 << MSI_DATA_DELIVERY_MODE_SHIFT)
+#define  MSI_DATA_DELIVERY_LOWPRI	(1 << MSI_DATA_DELIVERY_MODE_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT		14
+#define	 MSI_DATA_LEVEL_DEASSERT	(0 << MSI_DATA_LEVEL_SHIFT)
+#define	 MSI_DATA_LEVEL_ASSERT		(1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT		15
+#define  MSI_DATA_TRIGGER_EDGE		(0 << MSI_DATA_TRIGGER_SHIFT)
+#define  MSI_DATA_TRIGGER_LEVEL		(1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_BASE_HI		0
+#define MSI_ADDR_BASE_LO		0xfee00000
+
+#define MSI_ADDR_DEST_MODE_SHIFT	2
+#define  MSI_ADDR_DEST_MODE_PHYSICAL	(0 << MSI_ADDR_DEST_MODE_SHIFT)
+#define	 MSI_ADDR_DEST_MODE_LOGICAL	(1 << MSI_ADDR_DEST_MODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT	3
+#define  MSI_ADDR_REDIRECTION_CPU	(0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
+#define  MSI_ADDR_REDIRECTION_LOWPRI	(1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
+
+#define MSI_ADDR_DEST_ID_SHIFT		12
+#define	 MSI_ADDR_DEST_ID_MASK		0x00ffff0
+#define  MSI_ADDR_DEST_ID(dest)		(((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
+
+#endif /* ASM_MSIDEF_H */
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index f7a52e1..ea005c0 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -46,6 +46,7 @@
 header-y += comstats.h
 header-y += consolemap.h
 header-y += cycx_cfm.h
+header-y += dlm_device.h
 header-y += dm-ioctl.h
 header-y += dn.h
 header-y += dqblk_v1.h
@@ -104,6 +105,7 @@
 header-y += jffs2.h
 header-y += keyctl.h
 header-y += limits.h
+header-y += lock_dlm_plock.h
 header-y += magic.h
 header-y += major.h
 header-y += matroxfb.h
@@ -156,12 +158,10 @@
 header-y += ultrasound.h
 header-y += un.h
 header-y += utime.h
-header-y += utsname.h
 header-y += video_decoder.h
 header-y += video_encoder.h
 header-y += videotext.h
 header-y += vt.h
-header-y += wavefront.h
 header-y += wireless.h
 header-y += xattr.h
 header-y += x25.h
@@ -194,6 +194,7 @@
 unifdef-y += dccp.h
 unifdef-y += dirent.h
 unifdef-y += divert.h
+unifdef-y += dlm.h
 unifdef-y += elfcore.h
 unifdef-y += errno.h
 unifdef-y += errqueue.h
@@ -210,6 +211,7 @@
 unifdef-y += gameport.h
 unifdef-y += generic_serial.h
 unifdef-y += genhd.h
+unifdef-y += gfs2_ondisk.h
 unifdef-y += hayesesp.h
 unifdef-y += hdlcdrv.h
 unifdef-y += hdlc.h
@@ -333,6 +335,7 @@
 unifdef-y += usb_ch9.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += user.h
+unifdef-y += utsname.h
 unifdef-y += videodev2.h
 unifdef-y += videodev.h
 unifdef-y += wait.h
diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h
index 2ed2fd8..22eb936 100644
--- a/include/linux/ac97_codec.h
+++ b/include/linux/ac97_codec.h
@@ -331,8 +331,6 @@
 extern int ac97_probe_codec(struct ac97_codec *);
 extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
 extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
-extern int ac97_save_state(struct ac97_codec *codec);
-extern int ac97_restore_state(struct ac97_codec *codec);
 
 extern struct ac97_codec *ac97_alloc_codec(void);
 extern void ac97_release_codec(struct ac97_codec *codec);
@@ -346,9 +344,6 @@
 	void (*remove) (struct ac97_codec *codec, struct ac97_driver *driver);
 };
 
-extern int ac97_register_driver(struct ac97_driver *driver);
-extern void ac97_unregister_driver(struct ac97_driver *driver);
-
 /* quirk types */
 enum {
 	AC97_TUNE_DEFAULT = -1, /* use default from quirk list (not valid in list) */
diff --git a/include/linux/audit.h b/include/linux/audit.h
index c3aa097..b2ca666 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -75,7 +75,7 @@
 #define AUDIT_DAEMON_CONFIG     1203    /* Daemon config change */
 
 #define AUDIT_SYSCALL		1300	/* Syscall event */
-#define AUDIT_FS_WATCH		1301	/* Filesystem watch event */
+/* #define AUDIT_FS_WATCH	1301	 * Deprecated */
 #define AUDIT_PATH		1302	/* Filename path information */
 #define AUDIT_IPC		1303	/* IPC record */
 #define AUDIT_SOCKETCALL	1304	/* sys_socketcall arguments */
@@ -88,6 +88,7 @@
 #define AUDIT_MQ_SENDRECV	1313	/* POSIX MQ send/receive record type */
 #define AUDIT_MQ_NOTIFY		1314	/* POSIX MQ notify record type */
 #define AUDIT_MQ_GETSETATTR	1315	/* POSIX MQ get/set attribute record type */
+#define AUDIT_KERNEL_OTHER	1316	/* For use by 3rd party modules */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
diff --git a/include/linux/config.h b/include/linux/config.h
index a91f5e5..479ffb0 100644
--- a/include/linux/config.h
+++ b/include/linux/config.h
@@ -3,6 +3,7 @@
 /* This file is no longer in use and kept only for backward compatibility.
  * autoconf.h is now included via -imacros on the commandline
  */
+#warning Including config.h is deprecated.
 #include <linux/autoconf.h>
 
 #endif
diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
index 88dafa2..952bee7 100644
--- a/include/linux/debug_locks.h
+++ b/include/linux/debug_locks.h
@@ -43,6 +43,8 @@
 # define locking_selftest()	do { } while (0)
 #endif
 
+struct task_struct;
+
 #ifdef CONFIG_LOCKDEP
 extern void debug_show_all_locks(void);
 extern void debug_show_held_locks(struct task_struct *task);
diff --git a/include/linux/dlm.h b/include/linux/dlm.h
new file mode 100644
index 0000000..1b1dcb9
--- /dev/null
+++ b/include/linux/dlm.h
@@ -0,0 +1,302 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DLM_DOT_H__
+#define __DLM_DOT_H__
+
+/*
+ * Interface to Distributed Lock Manager (DLM)
+ * routines and structures to use DLM lockspaces
+ */
+
+/*
+ * Lock Modes
+ */
+
+#define DLM_LOCK_IV		-1	/* invalid */
+#define DLM_LOCK_NL		0	/* null */
+#define DLM_LOCK_CR		1	/* concurrent read */
+#define DLM_LOCK_CW		2	/* concurrent write */
+#define DLM_LOCK_PR		3	/* protected read */
+#define DLM_LOCK_PW		4	/* protected write */
+#define DLM_LOCK_EX		5	/* exclusive */
+
+/*
+ * Maximum size in bytes of a dlm_lock name
+ */
+
+#define DLM_RESNAME_MAXLEN	64
+
+/*
+ * Flags to dlm_lock
+ *
+ * DLM_LKF_NOQUEUE
+ *
+ * Do not queue the lock request on the wait queue if it cannot be granted
+ * immediately.  If the lock cannot be granted because of this flag, DLM will
+ * either return -EAGAIN from the dlm_lock call or will return 0 from
+ * dlm_lock and -EAGAIN in the lock status block when the AST is executed.
+ *
+ * DLM_LKF_CANCEL
+ *
+ * Used to cancel a pending lock request or conversion.  A converting lock is
+ * returned to its previously granted mode.
+ *
+ * DLM_LKF_CONVERT
+ *
+ * Indicates a lock conversion request.  For conversions the name and namelen
+ * are ignored and the lock ID in the LKSB is used to identify the lock.
+ *
+ * DLM_LKF_VALBLK
+ *
+ * Requests DLM to return the current contents of the lock value block in the
+ * lock status block.  When this flag is set in a lock conversion from PW or EX
+ * modes, DLM assigns the value specified in the lock status block to the lock
+ * value block of the lock resource.  The LVB is a DLM_LVB_LEN size array
+ * containing application-specific information.
+ *
+ * DLM_LKF_QUECVT
+ *
+ * Force a conversion request to be queued, even if it is compatible with
+ * the granted modes of other locks on the same resource.
+ *
+ * DLM_LKF_IVVALBLK
+ *
+ * Invalidate the lock value block.
+ *
+ * DLM_LKF_CONVDEADLK
+ *
+ * Allows the dlm to resolve conversion deadlocks internally by demoting the
+ * granted mode of a converting lock to NL.  The DLM_SBF_DEMOTED flag is
+ * returned for a conversion that's been effected by this.
+ *
+ * DLM_LKF_PERSISTENT
+ *
+ * Only relevant to locks originating in userspace.  A persistent lock will not
+ * be removed if the process holding the lock exits.
+ *
+ * DLM_LKF_NODLKWT
+ * DLM_LKF_NODLCKBLK
+ *
+ * net yet implemented
+ *
+ * DLM_LKF_EXPEDITE
+ *
+ * Used only with new requests for NL mode locks.  Tells the lock manager
+ * to grant the lock, ignoring other locks in convert and wait queues.
+ *
+ * DLM_LKF_NOQUEUEBAST
+ *
+ * Send blocking AST's before returning -EAGAIN to the caller.  It is only
+ * used along with the NOQUEUE flag.  Blocking AST's are not sent for failed
+ * NOQUEUE requests otherwise.
+ *
+ * DLM_LKF_HEADQUE
+ *
+ * Add a lock to the head of the convert or wait queue rather than the tail.
+ *
+ * DLM_LKF_NOORDER
+ *
+ * Disregard the standard grant order rules and grant a lock as soon as it
+ * is compatible with other granted locks.
+ *
+ * DLM_LKF_ORPHAN
+ *
+ * not yet implemented
+ *
+ * DLM_LKF_ALTPR
+ *
+ * If the requested mode cannot be granted immediately, try to grant the lock
+ * in PR mode instead.  If this alternate mode is granted instead of the
+ * requested mode, DLM_SBF_ALTMODE is returned in the lksb.
+ *
+ * DLM_LKF_ALTCW
+ *
+ * The same as ALTPR, but the alternate mode is CW.
+ *
+ * DLM_LKF_FORCEUNLOCK
+ *
+ * Unlock the lock even if it is converting or waiting or has sublocks.
+ * Only really for use by the userland device.c code.
+ *
+ */
+
+#define DLM_LKF_NOQUEUE		0x00000001
+#define DLM_LKF_CANCEL		0x00000002
+#define DLM_LKF_CONVERT		0x00000004
+#define DLM_LKF_VALBLK		0x00000008
+#define DLM_LKF_QUECVT		0x00000010
+#define DLM_LKF_IVVALBLK	0x00000020
+#define DLM_LKF_CONVDEADLK	0x00000040
+#define DLM_LKF_PERSISTENT	0x00000080
+#define DLM_LKF_NODLCKWT	0x00000100
+#define DLM_LKF_NODLCKBLK	0x00000200
+#define DLM_LKF_EXPEDITE	0x00000400
+#define DLM_LKF_NOQUEUEBAST	0x00000800
+#define DLM_LKF_HEADQUE		0x00001000
+#define DLM_LKF_NOORDER		0x00002000
+#define DLM_LKF_ORPHAN		0x00004000
+#define DLM_LKF_ALTPR		0x00008000
+#define DLM_LKF_ALTCW		0x00010000
+#define DLM_LKF_FORCEUNLOCK	0x00020000
+
+/*
+ * Some return codes that are not in errno.h
+ */
+
+#define DLM_ECANCEL		0x10001
+#define DLM_EUNLOCK		0x10002
+
+typedef void dlm_lockspace_t;
+
+/*
+ * Lock status block
+ *
+ * Use this structure to specify the contents of the lock value block.  For a
+ * conversion request, this structure is used to specify the lock ID of the
+ * lock.  DLM writes the status of the lock request and the lock ID assigned
+ * to the request in the lock status block.
+ *
+ * sb_lkid: the returned lock ID.  It is set on new (non-conversion) requests.
+ * It is available when dlm_lock returns.
+ *
+ * sb_lvbptr: saves or returns the contents of the lock's LVB according to rules
+ * shown for the DLM_LKF_VALBLK flag.
+ *
+ * sb_flags: DLM_SBF_DEMOTED is returned if in the process of promoting a lock,
+ * it was first demoted to NL to avoid conversion deadlock.
+ * DLM_SBF_VALNOTVALID is returned if the resource's LVB is marked invalid.
+ *
+ * sb_status: the returned status of the lock request set prior to AST
+ * execution.  Possible return values:
+ *
+ * 0 if lock request was successful
+ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
+ * -ENOMEM if there is no memory to process request
+ * -EINVAL if there are invalid parameters
+ * -DLM_EUNLOCK if unlock request was successful
+ * -DLM_ECANCEL if a cancel completed successfully
+ */
+
+#define DLM_SBF_DEMOTED		0x01
+#define DLM_SBF_VALNOTVALID	0x02
+#define DLM_SBF_ALTMODE		0x04
+
+struct dlm_lksb {
+	int 	 sb_status;
+	uint32_t sb_lkid;
+	char 	 sb_flags;
+	char *	 sb_lvbptr;
+};
+
+
+#ifdef __KERNEL__
+
+#define DLM_LSFL_NODIR		0x00000001
+
+/*
+ * dlm_new_lockspace
+ *
+ * Starts a lockspace with the given name.  If the named lockspace exists in
+ * the cluster, the calling node joins it.
+ */
+
+int dlm_new_lockspace(char *name, int namelen, dlm_lockspace_t **lockspace,
+		      uint32_t flags, int lvblen);
+
+/*
+ * dlm_release_lockspace
+ *
+ * Stop a lockspace.
+ */
+
+int dlm_release_lockspace(dlm_lockspace_t *lockspace, int force);
+
+/*
+ * dlm_lock
+ *
+ * Make an asyncronous request to acquire or convert a lock on a named
+ * resource.
+ *
+ * lockspace: context for the request
+ * mode: the requested mode of the lock (DLM_LOCK_)
+ * lksb: lock status block for input and async return values
+ * flags: input flags (DLM_LKF_)
+ * name: name of the resource to lock, can be binary
+ * namelen: the length in bytes of the resource name (MAX_RESNAME_LEN)
+ * parent: the lock ID of a parent lock or 0 if none
+ * lockast: function DLM executes when it completes processing the request
+ * astarg: argument passed to lockast and bast functions
+ * bast: function DLM executes when this lock later blocks another request
+ *
+ * Returns:
+ * 0 if request is successfully queued for processing
+ * -EINVAL if any input parameters are invalid
+ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
+ * -ENOMEM if there is no memory to process request
+ * -ENOTCONN if there is a communication error
+ *
+ * If the call to dlm_lock returns an error then the operation has failed and
+ * the AST routine will not be called.  If dlm_lock returns 0 it is still
+ * possible that the lock operation will fail. The AST routine will be called
+ * when the locking is complete and the status is returned in the lksb.
+ *
+ * If the AST routines or parameter are passed to a conversion operation then
+ * they will overwrite those values that were passed to a previous dlm_lock
+ * call.
+ *
+ * AST routines should not block (at least not for long), but may make
+ * any locking calls they please.
+ */
+
+int dlm_lock(dlm_lockspace_t *lockspace,
+	     int mode,
+	     struct dlm_lksb *lksb,
+	     uint32_t flags,
+	     void *name,
+	     unsigned int namelen,
+	     uint32_t parent_lkid,
+	     void (*lockast) (void *astarg),
+	     void *astarg,
+	     void (*bast) (void *astarg, int mode));
+
+/*
+ * dlm_unlock
+ *
+ * Asynchronously release a lock on a resource.  The AST routine is called
+ * when the resource is successfully unlocked.
+ *
+ * lockspace: context for the request
+ * lkid: the lock ID as returned in the lksb
+ * flags: input flags (DLM_LKF_)
+ * lksb: if NULL the lksb parameter passed to last lock request is used
+ * astarg: the arg used with the completion ast for the unlock
+ *
+ * Returns:
+ * 0 if request is successfully queued for processing
+ * -EINVAL if any input parameters are invalid
+ * -ENOTEMPTY if the lock still has sublocks
+ * -EBUSY if the lock is waiting for a remote lock operation
+ * -ENOTCONN if there is a communication error
+ */
+
+int dlm_unlock(dlm_lockspace_t *lockspace,
+	       uint32_t lkid,
+	       uint32_t flags,
+	       struct dlm_lksb *lksb,
+	       void *astarg);
+
+#endif				/* __KERNEL__ */
+
+#endif				/* __DLM_DOT_H__ */
+
diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h
new file mode 100644
index 0000000..2a2dd18
--- /dev/null
+++ b/include/linux/dlm_device.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+*******************************************************************************
+**
+**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
+**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
+**
+**  This copyrighted material is made available to anyone wishing to use,
+**  modify, copy, or redistribute it subject to the terms and conditions
+**  of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/* This is the device interface for dlm, most users will use a library
+ * interface.
+ */
+
+#define DLM_USER_LVB_LEN	32
+
+/* Version of the device interface */
+#define DLM_DEVICE_VERSION_MAJOR 5
+#define DLM_DEVICE_VERSION_MINOR 0
+#define DLM_DEVICE_VERSION_PATCH 0
+
+/* struct passed to the lock write */
+struct dlm_lock_params {
+	__u8 mode;
+	__u8 namelen;
+	__u16 flags;
+	__u32 lkid;
+	__u32 parent;
+        void __user *castparam;
+	void __user *castaddr;
+	void __user *bastparam;
+        void __user *bastaddr;
+	struct dlm_lksb __user *lksb;
+	char lvb[DLM_USER_LVB_LEN];
+	char name[0];
+};
+
+struct dlm_lspace_params {
+	__u32 flags;
+	__u32 minor;
+	char name[0];
+};
+
+struct dlm_write_request {
+	__u32 version[3];
+	__u8 cmd;
+	__u8 is64bit;
+	__u8 unused[2];
+
+	union  {
+		struct dlm_lock_params   lock;
+		struct dlm_lspace_params lspace;
+	} i;
+};
+
+/* struct read from the "device" fd,
+   consists mainly of userspace pointers for the library to use */
+struct dlm_lock_result {
+	__u32 length;
+	void __user * user_astaddr;
+	void __user * user_astparam;
+	struct dlm_lksb __user * user_lksb;
+	struct dlm_lksb lksb;
+	__u8 bast_mode;
+	__u8 unused[3];
+	/* Offsets may be zero if no data is present */
+	__u32 lvb_offset;
+};
+
+/* Commands passed to the device */
+#define DLM_USER_LOCK         1
+#define DLM_USER_UNLOCK       2
+#define DLM_USER_QUERY        3
+#define DLM_USER_CREATE_LOCKSPACE  4
+#define DLM_USER_REMOVE_LOCKSPACE  5
+
+/* Arbitrary length restriction */
+#define MAX_LS_NAME_LEN 64
+
+/* Lockspace flags */
+#define DLM_USER_LSFLG_AUTOFREE   1
+#define DLM_USER_LSFLG_FORCEFREE  2
+
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f53bf4f..34406ed 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -250,6 +250,8 @@
 #define FS_NOTAIL_FL			0x00008000 /* file tail should not be merged */
 #define FS_DIRSYNC_FL			0x00010000 /* dirsync behaviour (directories only) */
 #define FS_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
+#define FS_EXTENT_FL			0x00080000 /* Extents */
+#define FS_DIRECTIO_FL			0x00100000 /* Use direct i/o */
 #define FS_RESERVED_FL			0x80000000 /* reserved for ext2 lib */
 
 #define FS_FL_USER_VISIBLE		0x0003DFFF /* User visible flags */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 16fbe59..3da29e2 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -46,18 +46,17 @@
 
 struct gianfar_platform_data {
 	/* device specific information */
-	u32 device_flags;
-
+	u32	device_flags;
 	/* board specific information */
-	u32 board_flags;
-	u32 bus_id;
-	u32 phy_id;
-	u8 mac_addr[6];
+	u32	board_flags;
+	u32	bus_id;
+	u32	phy_id;
+	u8	mac_addr[6];
 };
 
 struct gianfar_mdio_data {
 	/* board specific information */
-	int irq[32];
+	int	irq[32];
 };
 
 /* Flags related to gianfar device features */
@@ -76,14 +75,13 @@
 
 struct fsl_i2c_platform_data {
 	/* device specific information */
-	u32 device_flags;
+	u32	device_flags;
 };
 
 /* Flags related to I2C device features */
 #define FSL_I2C_DEV_SEPARATE_DFSRR	0x00000001
 #define FSL_I2C_DEV_CLOCK_5200		0x00000002
 
-
 enum fsl_usb2_operating_modes {
 	FSL_USB2_MPH_HOST,
 	FSL_USB2_DR_HOST,
@@ -101,9 +99,9 @@
 
 struct fsl_usb2_platform_data {
 	/* board specific information */
-	enum fsl_usb2_operating_modes operating_mode;
-	enum fsl_usb2_phy_modes phy_mode;
-	unsigned int port_enables;
+	enum fsl_usb2_operating_modes	operating_mode;
+	enum fsl_usb2_phy_modes		phy_mode;
+	unsigned int			port_enables;
 };
 
 /* Flags in fsl_usb2_mph_platform_data */
@@ -121,5 +119,44 @@
 	u32	sysclk;
 };
 
-#endif				/* _FSL_DEVICE_H_ */
-#endif				/* __KERNEL__ */
+/* Ethernet interface (phy management and speed)
+*/
+enum enet_interface {
+	ENET_10_MII,		/* 10 Base T,   MII interface */
+	ENET_10_RMII,		/* 10 Base T,  RMII interface */
+	ENET_10_RGMII,		/* 10 Base T, RGMII interface */
+	ENET_100_MII,		/* 100 Base T,   MII interface */
+	ENET_100_RMII,		/* 100 Base T,  RMII interface */
+	ENET_100_RGMII,		/* 100 Base T, RGMII interface */
+	ENET_1000_GMII,		/* 1000 Base T,  GMII interface */
+	ENET_1000_RGMII,	/* 1000 Base T, RGMII interface */
+	ENET_1000_TBI,		/* 1000 Base T,   TBI interface */
+	ENET_1000_RTBI		/* 1000 Base T,  RTBI interface */
+};
+
+struct ucc_geth_platform_data {
+	/* device specific information */
+	u32			device_flags;
+	u32			phy_reg_addr;
+
+	/* board specific information */
+	u32			board_flags;
+	u8			rx_clock;
+	u8			tx_clock;
+	u32			phy_id;
+	enum enet_interface	phy_interface;
+	u32			phy_interrupt;
+	u8			mac_addr[6];
+};
+
+/* Flags related to UCC Gigabit Ethernet device features */
+#define FSL_UGETH_DEV_HAS_GIGABIT		0x00000001
+#define FSL_UGETH_DEV_HAS_COALESCE		0x00000002
+#define FSL_UGETH_DEV_HAS_RMON			0x00000004
+
+/* Flags in ucc_geth_platform_data */
+#define FSL_UGETH_BRD_HAS_PHY_INTR		0x00000001
+				/* if not set use a timer */
+
+#endif /* _FSL_DEVICE_H_ */
+#endif /* __KERNEL__ */
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
new file mode 100644
index 0000000..a7ae7c1
--- /dev/null
+++ b/include/linux/gfs2_ondisk.h
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __GFS2_ONDISK_DOT_H__
+#define __GFS2_ONDISK_DOT_H__
+
+#define GFS2_MAGIC		0x01161970
+#define GFS2_BASIC_BLOCK	512
+#define GFS2_BASIC_BLOCK_SHIFT	9
+
+/* Lock numbers of the LM_TYPE_NONDISK type */
+
+#define GFS2_MOUNT_LOCK		0
+#define GFS2_LIVE_LOCK		1
+#define GFS2_TRANS_LOCK		2
+#define GFS2_RENAME_LOCK	3
+
+/* Format numbers for various metadata types */
+
+#define GFS2_FORMAT_NONE	0
+#define GFS2_FORMAT_SB		100
+#define GFS2_FORMAT_RG		200
+#define GFS2_FORMAT_RB		300
+#define GFS2_FORMAT_DI		400
+#define GFS2_FORMAT_IN		500
+#define GFS2_FORMAT_LF		600
+#define GFS2_FORMAT_JD		700
+#define GFS2_FORMAT_LH		800
+#define GFS2_FORMAT_LD		900
+#define GFS2_FORMAT_LB		1000
+#define GFS2_FORMAT_EA		1600
+#define GFS2_FORMAT_ED		1700
+#define GFS2_FORMAT_QC		1400
+/* These are format numbers for entities contained in files */
+#define GFS2_FORMAT_RI		1100
+#define GFS2_FORMAT_DE		1200
+#define GFS2_FORMAT_QU		1500
+/* These are part of the superblock */
+#define GFS2_FORMAT_FS		1801
+#define GFS2_FORMAT_MULTI	1900
+
+/*
+ * An on-disk inode number
+ */
+
+struct gfs2_inum {
+	__be64 no_formal_ino;
+	__be64 no_addr;
+};
+
+static inline int gfs2_inum_equal(const struct gfs2_inum *ino1,
+				  const struct gfs2_inum *ino2)
+{
+	return ino1->no_formal_ino == ino2->no_formal_ino &&
+	       ino1->no_addr == ino2->no_addr;
+}
+
+/*
+ * Generic metadata head structure
+ * Every inplace buffer logged in the journal must start with this.
+ */
+
+#define GFS2_METATYPE_NONE	0
+#define GFS2_METATYPE_SB	1
+#define GFS2_METATYPE_RG	2
+#define GFS2_METATYPE_RB	3
+#define GFS2_METATYPE_DI	4
+#define GFS2_METATYPE_IN	5
+#define GFS2_METATYPE_LF	6
+#define GFS2_METATYPE_JD	7
+#define GFS2_METATYPE_LH	8
+#define GFS2_METATYPE_LD	9
+#define GFS2_METATYPE_LB	12
+#define GFS2_METATYPE_EA	10
+#define GFS2_METATYPE_ED	11
+#define GFS2_METATYPE_QC	14
+
+struct gfs2_meta_header {
+	__be32 mh_magic;
+	__be32 mh_type;
+	__be64 __pad0;		/* Was generation number in gfs1 */
+	__be32 mh_format;
+	__be32 __pad1;		/* Was incarnation number in gfs1 */
+};
+
+/*
+ * super-block structure
+ *
+ * It's probably good if SIZEOF_SB <= GFS2_BASIC_BLOCK (512 bytes)
+ *
+ * Order is important, need to be able to read old superblocks to do on-disk
+ * version upgrades.
+ */
+
+/* Address of superblock in GFS2 basic blocks */
+#define GFS2_SB_ADDR		128
+
+/* The lock number for the superblock (must be zero) */
+#define GFS2_SB_LOCK		0
+
+/* Requirement:  GFS2_LOCKNAME_LEN % 8 == 0
+   Includes: the fencing zero at the end */
+#define GFS2_LOCKNAME_LEN	64
+
+struct gfs2_sb {
+	struct gfs2_meta_header sb_header;
+
+	__be32 sb_fs_format;
+	__be32 sb_multihost_format;
+	__u32  __pad0;	/* Was superblock flags in gfs1 */
+
+	__be32 sb_bsize;
+	__be32 sb_bsize_shift;
+	__u32 __pad1;	/* Was journal segment size in gfs1 */
+
+	struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
+	struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
+	struct gfs2_inum sb_root_dir;
+
+	char sb_lockproto[GFS2_LOCKNAME_LEN];
+	char sb_locktable[GFS2_LOCKNAME_LEN];
+	/* In gfs1, quota and license dinodes followed */
+};
+
+/*
+ * resource index structure
+ */
+
+struct gfs2_rindex {
+	__be64 ri_addr;	/* grp block disk address */
+	__be32 ri_length;	/* length of rgrp header in fs blocks */
+	__u32 __pad;
+
+	__be64 ri_data0;	/* first data location */
+	__be32 ri_data;	/* num of data blocks in rgrp */
+
+	__be32 ri_bitbytes;	/* number of bytes in data bitmaps */
+
+	__u8 ri_reserved[64];
+};
+
+/*
+ * resource group header structure
+ */
+
+/* Number of blocks per byte in rgrp */
+#define GFS2_NBBY		4
+#define GFS2_BIT_SIZE		2
+#define GFS2_BIT_MASK		0x00000003
+
+#define GFS2_BLKST_FREE		0
+#define GFS2_BLKST_USED		1
+#define GFS2_BLKST_UNLINKED	2
+#define GFS2_BLKST_DINODE	3
+
+#define GFS2_RGF_JOURNAL	0x00000001
+#define GFS2_RGF_METAONLY	0x00000002
+#define GFS2_RGF_DATAONLY	0x00000004
+#define GFS2_RGF_NOALLOC	0x00000008
+
+struct gfs2_rgrp {
+	struct gfs2_meta_header rg_header;
+
+	__be32 rg_flags;
+	__be32 rg_free;
+	__be32 rg_dinodes;
+	__be32 __pad;
+	__be64 rg_igeneration;
+
+	__u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */
+};
+
+/*
+ * quota structure
+ */
+
+struct gfs2_quota {
+	__be64 qu_limit;
+	__be64 qu_warn;
+	__be64 qu_value;
+	__u8 qu_reserved[64];
+};
+
+/*
+ * dinode structure
+ */
+
+#define GFS2_MAX_META_HEIGHT	10
+#define GFS2_DIR_MAX_DEPTH	17
+
+#define DT2IF(dt) (((dt) << 12) & S_IFMT)
+#define IF2DT(sif) (((sif) & S_IFMT) >> 12)
+
+enum {
+	gfs2fl_Jdata		= 0,
+	gfs2fl_ExHash		= 1,
+	gfs2fl_Unused		= 2,
+	gfs2fl_EaIndirect	= 3,
+	gfs2fl_Directio		= 4,
+	gfs2fl_Immutable	= 5,
+	gfs2fl_AppendOnly	= 6,
+	gfs2fl_NoAtime		= 7,
+	gfs2fl_Sync		= 8,
+	gfs2fl_System		= 9,
+	gfs2fl_TruncInProg	= 29,
+	gfs2fl_InheritDirectio	= 30,
+	gfs2fl_InheritJdata	= 31,
+};
+
+/* Dinode flags */
+#define GFS2_DIF_JDATA			0x00000001
+#define GFS2_DIF_EXHASH			0x00000002
+#define GFS2_DIF_UNUSED			0x00000004  /* only in gfs1 */
+#define GFS2_DIF_EA_INDIRECT		0x00000008
+#define GFS2_DIF_DIRECTIO		0x00000010
+#define GFS2_DIF_IMMUTABLE		0x00000020
+#define GFS2_DIF_APPENDONLY		0x00000040
+#define GFS2_DIF_NOATIME		0x00000080
+#define GFS2_DIF_SYNC			0x00000100
+#define GFS2_DIF_SYSTEM			0x00000200 /* New in gfs2 */
+#define GFS2_DIF_TRUNC_IN_PROG		0x20000000 /* New in gfs2 */
+#define GFS2_DIF_INHERIT_DIRECTIO	0x40000000
+#define GFS2_DIF_INHERIT_JDATA		0x80000000
+
+struct gfs2_dinode {
+	struct gfs2_meta_header di_header;
+
+	struct gfs2_inum di_num;
+
+	__be32 di_mode;	/* mode of file */
+	__be32 di_uid;	/* owner's user id */
+	__be32 di_gid;	/* owner's group id */
+	__be32 di_nlink;	/* number of links to this file */
+	__be64 di_size;	/* number of bytes in file */
+	__be64 di_blocks;	/* number of blocks in file */
+	__be64 di_atime;	/* time last accessed */
+	__be64 di_mtime;	/* time last modified */
+	__be64 di_ctime;	/* time last changed */
+	__be32 di_major;	/* device major number */
+	__be32 di_minor;	/* device minor number */
+
+	/* This section varies from gfs1. Padding added to align with
+         * remainder of dinode
+	 */
+	__be64 di_goal_meta;	/* rgrp to alloc from next */
+	__be64 di_goal_data;	/* data block goal */
+	__be64 di_generation;	/* generation number for NFS */
+
+	__be32 di_flags;	/* GFS2_DIF_... */
+	__be32 di_payload_format;  /* GFS2_FORMAT_... */
+	__u16 __pad1;	/* Was ditype in gfs1 */
+	__be16 di_height;	/* height of metadata */
+	__u32 __pad2;	/* Unused incarnation number from gfs1 */
+
+	/* These only apply to directories  */
+	__u16 __pad3;	/* Padding */
+	__be16 di_depth;	/* Number of bits in the table */
+	__be32 di_entries;	/* The number of entries in the directory */
+
+	struct gfs2_inum __pad4; /* Unused even in current gfs1 */
+
+	__be64 di_eattr;	/* extended attribute block number */
+
+	__u8 di_reserved[56];
+};
+
+/*
+ * directory structure - many of these per directory file
+ */
+
+#define GFS2_FNAMESIZE		255
+#define GFS2_DIRENT_SIZE(name_len) ((sizeof(struct gfs2_dirent) + (name_len) + 7) & ~7)
+
+struct gfs2_dirent {
+	struct gfs2_inum de_inum;
+	__be32 de_hash;
+	__be16 de_rec_len;
+	__be16 de_name_len;
+	__be16 de_type;
+	__u8 __pad[14];
+};
+
+/*
+ * Header of leaf directory nodes
+ */
+
+struct gfs2_leaf {
+	struct gfs2_meta_header lf_header;
+
+	__be16 lf_depth;		/* Depth of leaf */
+	__be16 lf_entries;		/* Number of dirents in leaf */
+	__be32 lf_dirent_format;	/* Format of the dirents */
+	__be64 lf_next;			/* Next leaf, if overflow */
+
+	__u8 lf_reserved[64];
+};
+
+/*
+ * Extended attribute header format
+ */
+
+#define GFS2_EA_MAX_NAME_LEN	255
+#define GFS2_EA_MAX_DATA_LEN	65536
+
+#define GFS2_EATYPE_UNUSED	0
+#define GFS2_EATYPE_USR		1
+#define GFS2_EATYPE_SYS		2
+#define GFS2_EATYPE_SECURITY	3
+
+#define GFS2_EATYPE_LAST	3
+#define GFS2_EATYPE_VALID(x)	((x) <= GFS2_EATYPE_LAST)
+
+#define GFS2_EAFLAG_LAST	0x01	/* last ea in block */
+
+struct gfs2_ea_header {
+	__be32 ea_rec_len;
+	__be32 ea_data_len;
+	__u8 ea_name_len;	/* no NULL pointer after the string */
+	__u8 ea_type;		/* GFS2_EATYPE_... */
+	__u8 ea_flags;		/* GFS2_EAFLAG_... */
+	__u8 ea_num_ptrs;
+	__u32 __pad;
+};
+
+/*
+ * Log header structure
+ */
+
+#define GFS2_LOG_HEAD_UNMOUNT	0x00000001	/* log is clean */
+
+struct gfs2_log_header {
+	struct gfs2_meta_header lh_header;
+
+	__be64 lh_sequence;	/* Sequence number of this transaction */
+	__be32 lh_flags;	/* GFS2_LOG_HEAD_... */
+	__be32 lh_tail;		/* Block number of log tail */
+	__be32 lh_blkno;
+	__be32 lh_hash;
+};
+
+/*
+ * Log type descriptor
+ */
+
+#define GFS2_LOG_DESC_METADATA	300
+/* ld_data1 is the number of metadata blocks in the descriptor.
+   ld_data2 is unused. */
+
+#define GFS2_LOG_DESC_REVOKE	301
+/* ld_data1 is the number of revoke blocks in the descriptor.
+   ld_data2 is unused. */
+
+#define GFS2_LOG_DESC_JDATA	302
+/* ld_data1 is the number of data blocks in the descriptor.
+   ld_data2 is unused. */
+
+struct gfs2_log_descriptor {
+	struct gfs2_meta_header ld_header;
+
+	__be32 ld_type;		/* GFS2_LOG_DESC_... */
+	__be32 ld_length;	/* Number of buffers in this chunk */
+	__be32 ld_data1;	/* descriptor-specific field */
+	__be32 ld_data2;	/* descriptor-specific field */
+
+	__u8 ld_reserved[32];
+};
+
+/*
+ * Inum Range
+ * Describe a range of formal inode numbers allocated to
+ * one machine to assign to inodes.
+ */
+
+#define GFS2_INUM_QUANTUM	1048576
+
+struct gfs2_inum_range {
+	__be64 ir_start;
+	__be64 ir_length;
+};
+
+/*
+ * Statfs change
+ * Describes an change to the pool of free and allocated
+ * blocks.
+ */
+
+struct gfs2_statfs_change {
+	__be64 sc_total;
+	__be64 sc_free;
+	__be64 sc_dinodes;
+};
+
+/*
+ * Quota change
+ * Describes an allocation change for a particular
+ * user or group.
+ */
+
+#define GFS2_QCF_USER		0x00000001
+
+struct gfs2_quota_change {
+	__be64 qc_change;
+	__be32 qc_flags;	/* GFS2_QCF_... */
+	__be32 qc_id;
+};
+
+#ifdef __KERNEL__
+/* Translation functions */
+
+extern void gfs2_inum_in(struct gfs2_inum *no, const void *buf);
+extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf);
+extern void gfs2_sb_in(struct gfs2_sb *sb, const void *buf);
+extern void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf);
+extern void gfs2_rindex_out(const struct gfs2_rindex *ri, void *buf);
+extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf);
+extern void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf);
+extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf);
+extern void gfs2_quota_out(const struct gfs2_quota *qu, void *buf);
+extern void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf);
+extern void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf);
+extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf);
+extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf);
+extern void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf);
+extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf);
+extern void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf);
+extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf);
+extern void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf);
+extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf);
+
+/* Printing functions */
+
+extern void gfs2_rindex_print(const struct gfs2_rindex *ri);
+extern void gfs2_dinode_print(const struct gfs2_dinode *di);
+
+#endif /* __KERNEL__ */
+
+#endif /* __GFS2_ONDISK_DOT_H__ */
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 50d8b57..612472a 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -28,11 +28,16 @@
 
 #ifndef HARDIRQ_BITS
 #define HARDIRQ_BITS	12
+
+#ifndef MAX_HARDIRQS_PER_CPU
+#define MAX_HARDIRQS_PER_CPU NR_IRQS
+#endif
+
 /*
  * The hardirq mask has to be large enough to have space for potentially
  * all IRQ sources in the system nesting on a single CPU.
  */
-#if (1 << HARDIRQ_BITS) < NR_IRQS
+#if (1 << HARDIRQ_BITS) < MAX_HARDIRQS_PER_CPU
 # error HARDIRQ_BITS is too low!
 #endif
 #endif
diff --git a/include/linux/htirq.h b/include/linux/htirq.h
new file mode 100644
index 0000000..1f15ce2
--- /dev/null
+++ b/include/linux/htirq.h
@@ -0,0 +1,15 @@
+#ifndef LINUX_HTIRQ_H
+#define LINUX_HTIRQ_H
+
+/* Helper functions.. */
+void write_ht_irq_low(unsigned int irq, u32 data);
+void write_ht_irq_high(unsigned int irq, u32 data);
+u32  read_ht_irq_low(unsigned int irq);
+u32  read_ht_irq_high(unsigned int irq);
+void mask_ht_irq(unsigned int irq);
+void unmask_ht_irq(unsigned int irq);
+
+/* The arch hook for getting things started */
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
+
+#endif /* LINUX_HTIRQ_H */
diff --git a/include/linux/in.h b/include/linux/in.h
index d79fc75..2619859 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -40,6 +40,7 @@
 
   IPPROTO_ESP = 50,            /* Encapsulation Security Payload protocol */
   IPPROTO_AH = 51,             /* Authentication Header protocol       */
+  IPPROTO_BEETPH = 94,	       /* IP option pseudo header for BEET */
   IPPROTO_PIM    = 103,		/* Protocol Independent Multicast	*/
 
   IPPROTO_COMP   = 108,                /* Compression Header protocol */
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 6b25d36..ecee9bb 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -80,6 +80,8 @@
 #define	IPOPT_TS_TSANDADDR	1		/* timestamps and addresses */
 #define	IPOPT_TS_PRESPEC	3		/* specified modules only */
 
+#define IPV4_BEET_PHMAXLEN 8
+
 struct iphdr {
 #if defined(__LITTLE_ENDIAN_BITFIELD)
 	__u8	ihl:4,
@@ -123,4 +125,11 @@
 	__be16 cpi;
 };
 
+struct ip_beet_phdr {
+	__u8 nexthdr;
+	__u8 hdrlen;
+	__u8 padlen;
+	__u8 reserved;
+};
+
 #endif	/* _LINUX_IP_H */
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index d9e2b3f..636094c 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -2,7 +2,6 @@
 #define _LINUX_IPC_H
 
 #include <linux/types.h>
-#include <linux/kref.h>
 
 #define IPC_PRIVATE ((__kernel_key_t) 0)  
 
@@ -52,6 +51,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/kref.h>
+
 #define IPCMNI 32768  /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
 
 /* used by in-kernel data structures */
diff --git a/include/linux/ipsec.h b/include/linux/ipsec.h
index d3c5276..d17a630 100644
--- a/include/linux/ipsec.h
+++ b/include/linux/ipsec.h
@@ -12,7 +12,8 @@
 enum {
 	IPSEC_MODE_ANY		= 0,	/* We do not support this for SA */
 	IPSEC_MODE_TRANSPORT	= 1,
-	IPSEC_MODE_TUNNEL	= 2
+	IPSEC_MODE_TUNNEL	= 2,
+	IPSEC_MODE_BEET         = 3
 };
 
 enum {
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 48d3cb3..6f46360 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -59,6 +59,7 @@
 #define IRQ_NOAUTOEN		0x08000000	/* IRQ will not be enabled on request irq */
 #define IRQ_DELAYED_DISABLE	0x10000000	/* IRQ disable (masking) happens delayed. */
 #define IRQ_WAKEUP		0x20000000	/* IRQ triggers system wakeup */
+#define IRQ_MOVE_PENDING	0x40000000	/* need to re-target IRQ destination */
 
 struct proc_dir_entry;
 
@@ -132,7 +133,6 @@
  * @affinity:		IRQ affinity on SMP
  * @cpu:		cpu index useful for balancing
  * @pending_mask:	pending rebalanced interrupts
- * @move_irq:		need to re-target IRQ destination
  * @dir:		/proc/irq/ procfs entry
  * @affinity_entry:	/proc/irq/smp_affinity procfs entry on SMP
  *
@@ -159,7 +159,6 @@
 #endif
 #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
 	cpumask_t		pending_mask;
-	unsigned int		move_irq;	/* need to re-target IRQ dest */
 #endif
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *dir;
@@ -206,36 +205,7 @@
 
 void set_pending_irq(unsigned int irq, cpumask_t mask);
 void move_native_irq(int irq);
-
-#ifdef CONFIG_PCI_MSI
-/*
- * Wonder why these are dummies?
- * For e.g the set_ioapic_affinity_vector() calls the set_ioapic_affinity_irq()
- * counter part after translating the vector to irq info. We need to perform
- * this operation on the real irq, when we dont use vector, i.e when
- * pci_use_vector() is false.
- */
-static inline void move_irq(int irq)
-{
-}
-
-static inline void set_irq_info(int irq, cpumask_t mask)
-{
-}
-
-#else /* CONFIG_PCI_MSI */
-
-static inline void move_irq(int irq)
-{
-	move_native_irq(irq);
-}
-
-static inline void set_irq_info(int irq, cpumask_t mask)
-{
-	set_native_irq_info(irq, mask);
-}
-
-#endif /* CONFIG_PCI_MSI */
+void move_masked_irq(int irq);
 
 #else /* CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE */
 
@@ -247,21 +217,20 @@
 {
 }
 
-static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+static inline void move_masked_irq(int irq)
 {
 }
 
-static inline void set_irq_info(int irq, cpumask_t mask)
+static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
 {
-	set_native_irq_info(irq, mask);
 }
 
 #endif /* CONFIG_GENERIC_PENDING_IRQ */
 
 #else /* CONFIG_SMP */
 
-#define move_irq(x)
 #define move_native_irq(x)
+#define move_masked_irq(x)
 
 #endif /* CONFIG_SMP */
 
@@ -399,8 +368,22 @@
 	__set_irq_handler(irq, handle, 1);
 }
 
-/* Set/get chip/data for an IRQ: */
+/* Handle dynamic irq creation and destruction */
+extern int create_irq(void);
+extern void destroy_irq(unsigned int irq);
 
+/* Test to see if a driver has successfully requested an irq */
+static inline int irq_has_action(unsigned int irq)
+{
+	struct irq_desc *desc = irq_desc + irq;
+	return desc->action != NULL;
+}
+
+/* Dynamic irq helper functions */
+extern void dynamic_irq_init(unsigned int irq);
+extern void dynamic_irq_cleanup(unsigned int irq);
+
+/* Set/get chip/data for an IRQ: */
 extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
 extern int set_irq_data(unsigned int irq, void *data);
 extern int set_irq_chip_data(unsigned int irq, void *data);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d6a3d4b..d1af1dbe 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -109,6 +109,10 @@
 #define ATA_TAG_POISON		0xfafbfcfdU
 
 /* move to PCI layer? */
+#define PCI_VDEVICE(vendor, device)		\
+	PCI_VENDOR_ID_##vendor, (device),	\
+	PCI_ANY_ID, PCI_ANY_ID, 0, 0
+
 static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
 {
 	return &pdev->dev;
@@ -138,8 +142,9 @@
 	ATA_DFLAG_NCQ		= (1 << 3), /* device supports NCQ */
 	ATA_DFLAG_CFG_MASK	= (1 << 8) - 1,
 
-	ATA_DFLAG_PIO		= (1 << 8), /* device currently in PIO mode */
-	ATA_DFLAG_SUSPENDED	= (1 << 9), /* device suspended */
+	ATA_DFLAG_PIO		= (1 << 8), /* device limited to PIO mode */
+	ATA_DFLAG_NCQ_OFF	= (1 << 9), /* devied limited to non-NCQ mode */
+	ATA_DFLAG_SUSPENDED	= (1 << 10), /* device suspended */
 	ATA_DFLAG_INIT_MASK	= (1 << 16) - 1,
 
 	ATA_DFLAG_DETACH	= (1 << 16),
diff --git a/include/linux/lm_interface.h b/include/linux/lm_interface.h
new file mode 100644
index 0000000..1418fdc
--- /dev/null
+++ b/include/linux/lm_interface.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LM_INTERFACE_DOT_H__
+#define __LM_INTERFACE_DOT_H__
+
+
+typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data);
+
+/*
+ * lm_mount() flags
+ *
+ * LM_MFLAG_SPECTATOR
+ * GFS is asking to join the filesystem's lockspace, but it doesn't want to
+ * modify the filesystem.  The lock module shouldn't assign a journal to the FS
+ * mount.  It shouldn't send recovery callbacks to the FS mount.  If the node
+ * dies or withdraws, all locks can be wiped immediately.
+ */
+
+#define LM_MFLAG_SPECTATOR	0x00000001
+
+/*
+ * lm_lockstruct flags
+ *
+ * LM_LSFLAG_LOCAL
+ * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS
+ * can make single-node optimizations.
+ */
+
+#define LM_LSFLAG_LOCAL		0x00000001
+
+/*
+ * lm_lockname types
+ */
+
+#define LM_TYPE_RESERVED	0x00
+#define LM_TYPE_NONDISK		0x01
+#define LM_TYPE_INODE		0x02
+#define LM_TYPE_RGRP		0x03
+#define LM_TYPE_META		0x04
+#define LM_TYPE_IOPEN		0x05
+#define LM_TYPE_FLOCK		0x06
+#define LM_TYPE_PLOCK		0x07
+#define LM_TYPE_QUOTA		0x08
+#define LM_TYPE_JOURNAL		0x09
+
+/*
+ * lm_lock() states
+ *
+ * SHARED is compatible with SHARED, not with DEFERRED or EX.
+ * DEFERRED is compatible with DEFERRED, not with SHARED or EX.
+ */
+
+#define LM_ST_UNLOCKED		0
+#define LM_ST_EXCLUSIVE		1
+#define LM_ST_DEFERRED		2
+#define LM_ST_SHARED		3
+
+/*
+ * lm_lock() flags
+ *
+ * LM_FLAG_TRY
+ * Don't wait to acquire the lock if it can't be granted immediately.
+ *
+ * LM_FLAG_TRY_1CB
+ * Send one blocking callback if TRY is set and the lock is not granted.
+ *
+ * LM_FLAG_NOEXP
+ * GFS sets this flag on lock requests it makes while doing journal recovery.
+ * These special requests should not be blocked due to the recovery like
+ * ordinary locks would be.
+ *
+ * LM_FLAG_ANY
+ * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may
+ * also be granted in SHARED.  The preferred state is whichever is compatible
+ * with other granted locks, or the specified state if no other locks exist.
+ *
+ * LM_FLAG_PRIORITY
+ * Override fairness considerations.  Suppose a lock is held in a shared state
+ * and there is a pending request for the deferred state.  A shared lock
+ * request with the priority flag would be allowed to bypass the deferred
+ * request and directly join the other shared lock.  A shared lock request
+ * without the priority flag might be forced to wait until the deferred
+ * requested had acquired and released the lock.
+ */
+
+#define LM_FLAG_TRY		0x00000001
+#define LM_FLAG_TRY_1CB		0x00000002
+#define LM_FLAG_NOEXP		0x00000004
+#define LM_FLAG_ANY		0x00000008
+#define LM_FLAG_PRIORITY	0x00000010
+
+/*
+ * lm_lock() and lm_async_cb return flags
+ *
+ * LM_OUT_ST_MASK
+ * Masks the lower two bits of lock state in the returned value.
+ *
+ * LM_OUT_CACHEABLE
+ * The lock hasn't been released so GFS can continue to cache data for it.
+ *
+ * LM_OUT_CANCELED
+ * The lock request was canceled.
+ *
+ * LM_OUT_ASYNC
+ * The result of the request will be returned in an LM_CB_ASYNC callback.
+ */
+
+#define LM_OUT_ST_MASK		0x00000003
+#define LM_OUT_CACHEABLE	0x00000004
+#define LM_OUT_CANCELED		0x00000008
+#define LM_OUT_ASYNC		0x00000080
+#define LM_OUT_ERROR		0x00000100
+
+/*
+ * lm_callback_t types
+ *
+ * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S
+ * Blocking callback, a remote node is requesting the given lock in
+ * EXCLUSIVE, DEFERRED, or SHARED.
+ *
+ * LM_CB_NEED_RECOVERY
+ * The given journal needs to be recovered.
+ *
+ * LM_CB_DROPLOCKS
+ * Reduce the number of cached locks.
+ *
+ * LM_CB_ASYNC
+ * The given lock has been granted.
+ */
+
+#define LM_CB_NEED_E		257
+#define LM_CB_NEED_D		258
+#define LM_CB_NEED_S		259
+#define LM_CB_NEED_RECOVERY	260
+#define LM_CB_DROPLOCKS		261
+#define LM_CB_ASYNC		262
+
+/*
+ * lm_recovery_done() messages
+ */
+
+#define LM_RD_GAVEUP		308
+#define LM_RD_SUCCESS		309
+
+
+struct lm_lockname {
+	u64 ln_number;
+	unsigned int ln_type;
+};
+
+#define lm_name_equal(name1, name2) \
+	(((name1)->ln_number == (name2)->ln_number) && \
+	 ((name1)->ln_type == (name2)->ln_type)) \
+
+struct lm_async_cb {
+	struct lm_lockname lc_name;
+	int lc_ret;
+};
+
+struct lm_lockstruct;
+
+struct lm_lockops {
+	const char *lm_proto_name;
+
+	/*
+	 * Mount/Unmount
+	 */
+
+	int (*lm_mount) (char *table_name, char *host_data,
+			 lm_callback_t cb, void *cb_data,
+			 unsigned int min_lvb_size, int flags,
+			 struct lm_lockstruct *lockstruct,
+			 struct kobject *fskobj);
+
+	void (*lm_others_may_mount) (void *lockspace);
+
+	void (*lm_unmount) (void *lockspace);
+
+	void (*lm_withdraw) (void *lockspace);
+
+	/*
+	 * Lock oriented operations
+	 */
+
+	int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp);
+
+	void (*lm_put_lock) (void *lock);
+
+	unsigned int (*lm_lock) (void *lock, unsigned int cur_state,
+				 unsigned int req_state, unsigned int flags);
+
+	unsigned int (*lm_unlock) (void *lock, unsigned int cur_state);
+
+	void (*lm_cancel) (void *lock);
+
+	int (*lm_hold_lvb) (void *lock, char **lvbp);
+	void (*lm_unhold_lvb) (void *lock, char *lvb);
+
+	/*
+	 * Posix Lock oriented operations
+	 */
+
+	int (*lm_plock_get) (void *lockspace, struct lm_lockname *name,
+			     struct file *file, struct file_lock *fl);
+
+	int (*lm_plock) (void *lockspace, struct lm_lockname *name,
+			 struct file *file, int cmd, struct file_lock *fl);
+
+	int (*lm_punlock) (void *lockspace, struct lm_lockname *name,
+			   struct file *file, struct file_lock *fl);
+
+	/*
+	 * Client oriented operations
+	 */
+
+	void (*lm_recovery_done) (void *lockspace, unsigned int jid,
+				  unsigned int message);
+
+	struct module *lm_owner;
+};
+
+/*
+ * lm_mount() return values
+ *
+ * ls_jid - the journal ID this node should use
+ * ls_first - this node is the first to mount the file system
+ * ls_lvb_size - size in bytes of lock value blocks
+ * ls_lockspace - lock module's context for this file system
+ * ls_ops - lock module's functions
+ * ls_flags - lock module features
+ */
+
+struct lm_lockstruct {
+	unsigned int ls_jid;
+	unsigned int ls_first;
+	unsigned int ls_lvb_size;
+	void *ls_lockspace;
+	const struct lm_lockops *ls_ops;
+	int ls_flags;
+};
+
+/*
+ * Lock module bottom interface.  A lock module makes itself available to GFS
+ * with these functions.
+ */
+
+int gfs2_register_lockproto(const struct lm_lockops *proto);
+void gfs2_unregister_lockproto(const struct lm_lockops *proto);
+
+/*
+ * Lock module top interface.  GFS calls these functions when mounting or
+ * unmounting a file system.
+ */
+
+int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
+			 lm_callback_t cb, void *cb_data,
+			 unsigned int min_lvb_size, int flags,
+			 struct lm_lockstruct *lockstruct,
+			 struct kobject *fskobj);
+
+void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct);
+
+void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct);
+
+#endif /* __LM_INTERFACE_DOT_H__ */
+
diff --git a/include/linux/lock_dlm_plock.h b/include/linux/lock_dlm_plock.h
new file mode 100644
index 0000000..fc34151
--- /dev/null
+++ b/include/linux/lock_dlm_plock.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __LOCK_DLM_PLOCK_DOT_H__
+#define __LOCK_DLM_PLOCK_DOT_H__
+
+#define GDLM_PLOCK_MISC_NAME		"lock_dlm_plock"
+
+#define GDLM_PLOCK_VERSION_MAJOR	1
+#define GDLM_PLOCK_VERSION_MINOR	1
+#define GDLM_PLOCK_VERSION_PATCH	0
+
+enum {
+	GDLM_PLOCK_OP_LOCK = 1,
+	GDLM_PLOCK_OP_UNLOCK,
+	GDLM_PLOCK_OP_GET,
+};
+
+struct gdlm_plock_info {
+	__u32 version[3];
+	__u8 optype;
+	__u8 ex;
+	__u8 wait;
+	__u8 pad;
+	__u32 pid;
+	__s32 nodeid;
+	__s32 rv;
+	__u32 fsid;
+	__u64 number;
+	__u64 start;
+	__u64 end;
+	__u64 owner;
+};
+
+#endif
+
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 47b7dbd..2909619 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -37,17 +37,15 @@
  * Lockd host handle (used both by the client and server personality).
  */
 struct nlm_host {
-	struct nlm_host *	h_next;		/* linked list (hash table) */
+	struct hlist_node	h_hash;		/* doubly linked list */
 	struct sockaddr_in	h_addr;		/* peer address */
 	struct rpc_clnt	*	h_rpcclnt;	/* RPC client to talk to peer */
-	char			h_name[20];	/* remote hostname */
+	char *			h_name;		/* remote hostname */
 	u32			h_version;	/* interface version */
 	unsigned short		h_proto;	/* transport proto */
 	unsigned short		h_reclaiming : 1,
 				h_server     : 1, /* server side, not client side */
-				h_inuse      : 1,
-				h_killed     : 1,
-				h_monitored  : 1;
+				h_inuse      : 1;
 	wait_queue_head_t	h_gracewait;	/* wait while reclaiming */
 	struct rw_semaphore	h_rwsem;	/* Reboot recovery lock */
 	u32			h_state;	/* pseudo-state counter */
@@ -61,6 +59,16 @@
 	spinlock_t		h_lock;
 	struct list_head	h_granted;	/* Locks in GRANTED state */
 	struct list_head	h_reclaim;	/* Locks in RECLAIM state */
+	struct nsm_handle *	h_nsmhandle;	/* NSM status handle */
+};
+
+struct nsm_handle {
+	struct list_head	sm_link;
+	atomic_t		sm_count;
+	char *			sm_name;
+	struct sockaddr_in	sm_addr;
+	unsigned int		sm_monitored : 1,
+				sm_sticky : 1;	/* don't unmonitor */
 };
 
 /*
@@ -96,15 +104,14 @@
  * an NFS client.
  */
 struct nlm_file {
-	struct nlm_file *	f_next;		/* linked list */
+	struct hlist_node	f_list;		/* linked list */
 	struct nfs_fh		f_handle;	/* NFS file handle */
 	struct file *		f_file;		/* VFS file pointer */
 	struct nlm_share *	f_shares;	/* DOS shares */
-	struct nlm_block *	f_blocks;	/* blocked locks */
+	struct list_head	f_blocks;	/* blocked locks */
 	unsigned int		f_locks;	/* guesstimate # of locks */
 	unsigned int		f_count;	/* reference count */
-	struct semaphore	f_sema;		/* avoid concurrent access */
-	int		       	f_hash;		/* hash of f_handle */
+	struct mutex		f_mutex;	/* avoid concurrent access */
 };
 
 /*
@@ -114,26 +121,18 @@
 #define NLM_NEVER		(~(unsigned long) 0)
 struct nlm_block {
 	struct kref		b_count;	/* Reference count */
-	struct nlm_block *	b_next;		/* linked list (all blocks) */
-	struct nlm_block *	b_fnext;	/* linked list (per file) */
+	struct list_head	b_list;		/* linked list of all blocks */
+	struct list_head	b_flist;	/* linked list (per file) */
 	struct nlm_rqst	*	b_call;		/* RPC args & callback info */
 	struct svc_serv *	b_daemon;	/* NLM service */
 	struct nlm_host *	b_host;		/* host handle for RPC clnt */
 	unsigned long		b_when;		/* next re-xmit */
 	unsigned int		b_id;		/* block id */
-	unsigned char		b_queued;	/* re-queued */
 	unsigned char		b_granted;	/* VFS granted lock */
 	struct nlm_file *	b_file;		/* file in question */
 };
 
 /*
- * Valid actions for nlmsvc_traverse_files
- */
-#define NLM_ACT_CHECK		0		/* check for locks */
-#define NLM_ACT_MARK		1		/* mark & sweep */
-#define NLM_ACT_UNLOCK		2		/* release all locks */
-
-/*
  * Global variables
  */
 extern struct rpc_program	nlm_program;
@@ -143,6 +142,7 @@
 #endif
 extern int			nlmsvc_grace_period;
 extern unsigned long		nlmsvc_timeout;
+extern int			nsm_use_hostnames;
 
 /*
  * Lockd client functions
@@ -155,24 +155,33 @@
 void		  nlmclnt_finish_block(struct nlm_wait *block);
 int		  nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
 u32		  nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
-void		  nlmclnt_recovery(struct nlm_host *, u32);
+void		  nlmclnt_recovery(struct nlm_host *);
 int		  nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
+void		  nlmclnt_next_cookie(struct nlm_cookie *);
 
 /*
  * Host cache
  */
-struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int);
-struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *);
-struct nlm_host * nlm_lookup_host(int server, struct sockaddr_in *, int, int);
+struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int);
+struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int);
+struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int, const char *, int);
 struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 void		  nlm_rebind_host(struct nlm_host *);
 struct nlm_host * nlm_get_host(struct nlm_host *);
 void		  nlm_release_host(struct nlm_host *);
 void		  nlm_shutdown_hosts(void);
-extern struct nlm_host *nlm_find_client(void);
+extern void	  nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32);
+struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int);
+void		  nsm_release(struct nsm_handle *);
 
 
 /*
+ * This is used in garbage collection and resource reclaim
+ * A return value != 0 means destroy the lock/block/share
+ */
+typedef int	  (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref);
+
+/*
  * Server-side lock handling
  */
 u32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
@@ -183,8 +192,8 @@
 u32		  nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
 unsigned long	  nlmsvc_retry_blocked(void);
 void		  nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
-					int action);
-void	  nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32);
+					nlm_host_match_fn_t match);
+void		  nlmsvc_grant_reply(struct nlm_cookie *, u32);
 
 /*
  * File handling for the server personality
diff --git a/include/linux/lockd/share.h b/include/linux/lockd/share.h
index c75a424..cd7816e 100644
--- a/include/linux/lockd/share.h
+++ b/include/linux/lockd/share.h
@@ -25,6 +25,7 @@
 					       struct nlm_args *);
 u32	nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
 					       struct nlm_args *);
-void	nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int);
+void	nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
+					       nlm_host_match_fn_t);
 
 #endif /* LINUX_LOCKD_SHARE_H */
diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h
index 1080bb6..fc61d40 100644
--- a/include/linux/lockd/sm_inter.h
+++ b/include/linux/lockd/sm_inter.h
@@ -28,7 +28,8 @@
 	u32		prog;		/* RPC callback info */
 	u32		vers;
 	u32		proc;
-	u32		proto;		/* protocol (udp/tcp) plus server/client flag */
+
+	char *		mon_name;
 };
 
 /*
@@ -41,6 +42,6 @@
 
 int		nsm_monitor(struct nlm_host *);
 int		nsm_unmonitor(struct nlm_host *);
-extern u32	nsm_local_state;
+extern int	nsm_local_state;
 
 #endif /* LINUX_LOCKD_SM_INTER_H */
diff --git a/include/linux/msi.h b/include/linux/msi.h
new file mode 100644
index 0000000..c7ef943
--- /dev/null
+++ b/include/linux/msi.h
@@ -0,0 +1,49 @@
+#ifndef LINUX_MSI_H
+#define LINUX_MSI_H
+
+struct msi_msg {
+	u32	address_lo;	/* low 32 bits of msi message address */
+	u32	address_hi;	/* high 32 bits of msi message address */
+	u32	data;		/* 16 bits of msi message data */
+};
+
+/* Heper functions */
+extern void mask_msi_irq(unsigned int irq);
+extern void unmask_msi_irq(unsigned int irq);
+extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+struct msi_desc {
+	struct {
+		__u8	type	: 5; 	/* {0: unused, 5h:MSI, 11h:MSI-X} */
+		__u8	maskbit	: 1; 	/* mask-pending bit supported ?   */
+		__u8	unused	: 1;
+		__u8	is_64	: 1;	/* Address size: 0=32bit 1=64bit  */
+		__u8	pos;	 	/* Location of the msi capability */
+		__u16	entry_nr;    	/* specific enabled entry 	  */
+		unsigned default_irq;	/* default pre-assigned irq	  */
+	}msi_attrib;
+
+	struct {
+		__u16	head;
+		__u16	tail;
+	}link;
+
+	void __iomem *mask_base;
+	struct pci_dev *dev;
+
+#ifdef CONFIG_PM
+	/* PM save area for MSIX address/data */
+	struct msi_msg msg_save;
+#endif
+};
+
+/*
+ * The arch hook for setup up msi irqs
+ */
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+void arch_teardown_msi_irq(unsigned int irq);
+
+
+#endif /* LINUX_MSI_H */
diff --git a/include/linux/netfilter_bridge/ebt_mark_t.h b/include/linux/netfilter_bridge/ebt_mark_t.h
index 110fec6..6270f6f 100644
--- a/include/linux/netfilter_bridge/ebt_mark_t.h
+++ b/include/linux/netfilter_bridge/ebt_mark_t.h
@@ -1,6 +1,18 @@
 #ifndef __LINUX_BRIDGE_EBT_MARK_T_H
 #define __LINUX_BRIDGE_EBT_MARK_T_H
 
+/* The target member is reused for adding new actions, the
+ * value of the real target is -1 to -NUM_STANDARD_TARGETS.
+ * For backward compatibility, the 4 lsb (2 would be enough,
+ * but let's play it safe) are kept to designate this target.
+ * The remaining bits designate the action. By making the set
+ * action 0xfffffff0, the result will look ok for older
+ * versions. [September 2006] */
+#define MARK_SET_VALUE (0xfffffff0)
+#define MARK_OR_VALUE  (0xffffffe0)
+#define MARK_AND_VALUE (0xffffffd0)
+#define MARK_XOR_VALUE (0xffffffc0)
+
 struct ebt_mark_t_info
 {
 	unsigned long mark;
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index ce02c98..5b63a23 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -77,7 +77,7 @@
 #define SO_ORIGINAL_DST 80
 
 #ifdef __KERNEL__
-extern int ip_route_me_harder(struct sk_buff **pskb);
+extern int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type);
 extern int ip_xfrm_me_harder(struct sk_buff **pskb);
 extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
 				   unsigned int dataoff, u_int8_t protocol);
diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h
index b75bb1b3..f0cc777 100644
--- a/include/linux/nfsd/const.h
+++ b/include/linux/nfsd/const.h
@@ -20,17 +20,31 @@
 #define NFSSVC_MAXVERS		3
 
 /*
- * Maximum blocksize supported by daemon currently at 32K
+ * Maximum blocksizes supported by daemon under various circumstances.
  */
-#define NFSSVC_MAXBLKSIZE	(32*1024)
+#define NFSSVC_MAXBLKSIZE	RPCSVC_MAXPAYLOAD
+/* NFSv2 is limited by the protocol specification, see RFC 1094 */
+#define NFSSVC_MAXBLKSIZE_V2	(8*1024)
 
 #ifdef __KERNEL__
 
+#include <linux/sunrpc/msg_prot.h>
+
 #ifndef NFS_SUPER_MAGIC
 # define NFS_SUPER_MAGIC	0x6969
 #endif
 
-#define NFSD_BUFSIZE		(1024 + NFSSVC_MAXBLKSIZE)
+/*
+ * Largest number of bytes we need to allocate for an NFS
+ * call or reply.  Used to control buffer sizes.  We use
+ * the length of v3 WRITE, READDIR and READDIR replies
+ * which are an RPC header, up to 26 XDR units of reply
+ * data, and some page data.
+ *
+ * Note that accuracy here doesn't matter too much as the
+ * size is rounded up to a page size when allocating space.
+ */
+#define NFSD_BUFSIZE		((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE)
 
 #ifdef CONFIG_NFSD_V4
 # define NFSSVC_XDRSIZE		NFS4_SVC_XDRSIZE
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index d2a8abb..6e78ea9 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -45,15 +45,36 @@
 
 #ifdef __KERNEL__
 
+/*
+ * FS Locations
+ */
+
+#define MAX_FS_LOCATIONS	128
+
+struct nfsd4_fs_location {
+	char *hosts; /* colon separated list of hosts */
+	char *path;  /* slash separated list of path components */
+};
+
+struct nfsd4_fs_locations {
+	uint32_t locations_count;
+	struct nfsd4_fs_location *locations;
+/* If we're not actually serving this data ourselves (only providing a
+ * list of replicas that do serve it) then we set "migrated": */
+	int migrated;
+};
+
 struct svc_export {
 	struct cache_head	h;
 	struct auth_domain *	ex_client;
 	int			ex_flags;
 	struct vfsmount *	ex_mnt;
 	struct dentry *		ex_dentry;
+	char *			ex_path;
 	uid_t			ex_anon_uid;
 	gid_t			ex_anon_gid;
 	int			ex_fsid;
+	struct nfsd4_fs_locations ex_fslocs;
 };
 
 /* an "export key" (expkey) maps a filehandlefragement to an
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index e1dbc86..d0d4aae 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -145,6 +145,7 @@
 void nfsd_reset_versions(void);
 int nfsd_create_serv(void);
 
+extern int nfsd_max_blksize;
 
 /* 
  * NFSv4 State
@@ -215,6 +216,7 @@
 #define	nfserr_clid_inuse	__constant_htonl(NFSERR_CLID_INUSE)
 #define	nfserr_stale_clientid	__constant_htonl(NFSERR_STALE_CLIENTID)
 #define	nfserr_resource		__constant_htonl(NFSERR_RESOURCE)
+#define	nfserr_moved		__constant_htonl(NFSERR_MOVED)
 #define	nfserr_nofilehandle	__constant_htonl(NFSERR_NOFILEHANDLE)
 #define	nfserr_minor_vers_mismatch	__constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
 #define nfserr_share_denied	__constant_htonl(NFSERR_SHARE_DENIED)
@@ -291,7 +293,6 @@
 /*
  * The following attributes are currently not supported by the NFSv4 server:
  *    ARCHIVE       (deprecated anyway)
- *    FS_LOCATIONS  (will be supported eventually)
  *    HIDDEN        (unlikely to be supported any time soon)
  *    MIMETYPE      (unlikely to be supported any time soon)
  *    QUOTA_*       (will be supported in a forthcoming patch)
@@ -307,7 +308,7 @@
  | FATTR4_WORD0_ACLSUPPORT      | FATTR4_WORD0_CANSETTIME   | FATTR4_WORD0_CASE_INSENSITIVE \
  | FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED                             \
  | FATTR4_WORD0_FILEHANDLE      | FATTR4_WORD0_FILEID       | FATTR4_WORD0_FILES_AVAIL      \
- | FATTR4_WORD0_FILES_FREE      | FATTR4_WORD0_FILES_TOTAL  | FATTR4_WORD0_HOMOGENEOUS      \
+ | FATTR4_WORD0_FILES_FREE      | FATTR4_WORD0_FILES_TOTAL  | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS      \
  | FATTR4_WORD0_MAXFILESIZE     | FATTR4_WORD0_MAXLINK      | FATTR4_WORD0_MAXNAME          \
  | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE     | FATTR4_WORD0_ACL)
 
diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
index a38f9d7..0e53de8 100644
--- a/include/linux/nfsd/xdr.h
+++ b/include/linux/nfsd/xdr.h
@@ -30,7 +30,6 @@
 	struct svc_fh		fh;
 	__u32			offset;
 	__u32			count;
-	struct kvec		vec[RPCSVC_MAXPAGES];
 	int			vlen;
 };
 
@@ -38,7 +37,6 @@
 	svc_fh			fh;
 	__u32			offset;
 	int			len;
-	struct kvec		vec[RPCSVC_MAXPAGES];
 	int			vlen;
 };
 
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
index a432274..474d882 100644
--- a/include/linux/nfsd/xdr3.h
+++ b/include/linux/nfsd/xdr3.h
@@ -33,7 +33,6 @@
 	struct svc_fh		fh;
 	__u64			offset;
 	__u32			count;
-	struct kvec		vec[RPCSVC_MAXPAGES];
 	int			vlen;
 };
 
@@ -43,7 +42,6 @@
 	__u32			count;
 	int			stable;
 	__u32			len;
-	struct kvec		vec[RPCSVC_MAXPAGES];
 	int			vlen;
 };
 
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 77adba7..66e6427 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -241,7 +241,6 @@
 	stateid_t	rd_stateid;         /* request */
 	u64		rd_offset;          /* request */
 	u32		rd_length;          /* request */
-	struct kvec	rd_iov[RPCSVC_MAXPAGES];
 	int		rd_vlen;
 	struct file     *rd_filp;
 	
@@ -326,7 +325,6 @@
 	u64		wr_offset;          /* request */
 	u32		wr_stable_how;      /* request */
 	u32		wr_buflen;          /* request */
-	struct kvec	wr_vec[RPCSVC_MAXPAGES]; /* request */
 	int		wr_vlen;
 
 	u32		wr_bytes_written;   /* response */
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 7ff386a..10a43ed 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -12,9 +12,10 @@
 #include <linux/errno.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
+#include <linux/srcu.h>
 
 /*
- * Notifier chains are of three types:
+ * Notifier chains are of four types:
  *
  *	Atomic notifier chains: Chain callbacks run in interrupt/atomic
  *		context. Callouts are not allowed to block.
@@ -23,13 +24,27 @@
  *	Raw notifier chains: There are no restrictions on callbacks,
  *		registration, or unregistration.  All locking and protection
  *		must be provided by the caller.
+ *	SRCU notifier chains: A variant of blocking notifier chains, with
+ *		the same restrictions.
  *
  * atomic_notifier_chain_register() may be called from an atomic context,
- * but blocking_notifier_chain_register() must be called from a process
- * context.  Ditto for the corresponding _unregister() routines.
+ * but blocking_notifier_chain_register() and srcu_notifier_chain_register()
+ * must be called from a process context.  Ditto for the corresponding
+ * _unregister() routines.
  *
- * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister()
- * _must not_ be called from within the call chain.
+ * atomic_notifier_chain_unregister(), blocking_notifier_chain_unregister(),
+ * and srcu_notifier_chain_unregister() _must not_ be called from within
+ * the call chain.
+ *
+ * SRCU notifier chains are an alternative form of blocking notifier chains.
+ * They use SRCU (Sleepable Read-Copy Update) instead of rw-semaphores for
+ * protection of the chain links.  This means there is _very_ low overhead
+ * in srcu_notifier_call_chain(): no cache bounces and no memory barriers.
+ * As compensation, srcu_notifier_chain_unregister() is rather expensive.
+ * SRCU notifier chains should be used when the chain will be called very
+ * often but notifier_blocks will seldom be removed.  Also, SRCU notifier
+ * chains are slightly more difficult to use because they require special
+ * runtime initialization.
  */
 
 struct notifier_block {
@@ -52,6 +67,12 @@
 	struct notifier_block *head;
 };
 
+struct srcu_notifier_head {
+	struct mutex mutex;
+	struct srcu_struct srcu;
+	struct notifier_block *head;
+};
+
 #define ATOMIC_INIT_NOTIFIER_HEAD(name) do {	\
 		spin_lock_init(&(name)->lock);	\
 		(name)->head = NULL;		\
@@ -64,6 +85,11 @@
 		(name)->head = NULL;		\
 	} while (0)
 
+/* srcu_notifier_heads must be initialized and cleaned up dynamically */
+extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
+#define srcu_cleanup_notifier_head(name)	\
+		cleanup_srcu_struct(&(name)->srcu);
+
 #define ATOMIC_NOTIFIER_INIT(name) {				\
 		.lock = __SPIN_LOCK_UNLOCKED(name.lock),	\
 		.head = NULL }
@@ -72,6 +98,7 @@
 		.head = NULL }
 #define RAW_NOTIFIER_INIT(name)	{				\
 		.head = NULL }
+/* srcu_notifier_heads cannot be initialized statically */
 
 #define ATOMIC_NOTIFIER_HEAD(name)				\
 	struct atomic_notifier_head name =			\
@@ -91,6 +118,8 @@
 		struct notifier_block *);
 extern int raw_notifier_chain_register(struct raw_notifier_head *,
 		struct notifier_block *);
+extern int srcu_notifier_chain_register(struct srcu_notifier_head *,
+		struct notifier_block *);
 
 extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *,
 		struct notifier_block *);
@@ -98,6 +127,8 @@
 		struct notifier_block *);
 extern int raw_notifier_chain_unregister(struct raw_notifier_head *,
 		struct notifier_block *);
+extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *,
+		struct notifier_block *);
 
 extern int atomic_notifier_call_chain(struct atomic_notifier_head *,
 		unsigned long val, void *v);
@@ -105,6 +136,8 @@
 		unsigned long val, void *v);
 extern int raw_notifier_call_chain(struct raw_notifier_head *,
 		unsigned long val, void *v);
+extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
+		unsigned long val, void *v);
 
 #define NOTIFY_DONE		0x0000		/* Don't care */
 #define NOTIFY_OK		0x0001		/* Suits me */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4431ce4..5c604f5 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -595,6 +595,7 @@
 	u16	entry;	/* driver uses to specify entry, OS writes */
 };
 
+
 #ifndef CONFIG_PCI_MSI
 static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -613,6 +614,12 @@
 extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
 #endif
 
+#ifdef CONFIG_HT_IRQ
+/* The functions a driver should call */
+int  ht_create_irq(struct pci_dev *dev, int idx);
+void ht_destroy_irq(unsigned int irq);
+#endif /* CONFIG_HT_IRQ */
+
 extern void pci_block_user_cfg_access(struct pci_dev *dev);
 extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
 
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 7d0e26c..c312a12 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -12,6 +12,11 @@
  *	PCI Local Bus Specification
  *	PCI to PCI Bridge Specification
  *	PCI System Design Guide
+ *
+ * 	For hypertransport information, please consult the following manuals
+ * 	from http://www.hypertransport.org
+ *
+ *	The Hypertransport I/O Link Specification
  */
 
 #ifndef LINUX_PCI_REGS_H
@@ -463,4 +468,20 @@
 #define PCI_PWR_CAP		12	/* Capability */
 #define  PCI_PWR_CAP_BUDGET(x)	((x) & 1)	/* Included in system budget */
 
+/* Hypertransport sub capability types */
+#define HT_CAPTYPE_SLAVE	0x00	/* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST		0x20	/* Host/Secondary link configuration */
+#define HT_CAPTYPE_IRQ		0x80	/* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40	0xA0	/* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2	/* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP	0x90	/* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF	0x98	/* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING	0xA8	/* MSI Mapping Capability */
+#define HT_CAPTYPE_DIRECT_ROUTE	0xB0	/* Direct routing configuration */
+#define HT_CAPTYPE_VCSET	0xB8	/* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY	0xC0	/* Retry on error configuration */
+#define HT_CAPTYPE_GEN3		0xD0	/* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM		0xE0	/* Hypertransport powermanagement configuration */
+
+
 #endif /* LINUX_PCI_REGS_H */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index b4ca73d..c6b7485 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -19,7 +19,7 @@
  *
  * Author: Dipankar Sarma <dipankar@in.ibm.com>
  * 
- * Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
+ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
  * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
  * Papers:
  * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
@@ -66,6 +66,8 @@
 	long	completed;	/* Number of the last completed batch         */
 	int	next_pending;	/* Is the next batch already waiting?         */
 
+	int	signaled;
+
 	spinlock_t	lock	____cacheline_internodealigned_in_smp;
 	cpumask_t	cpumask; /* CPUs that need to switch in order    */
 	                         /* for current batch to proceed.        */
@@ -106,9 +108,6 @@
 	long		blimit;		 /* Upper limit on a processed batch */
 	int cpu;
 	struct rcu_head barrier;
-#ifdef CONFIG_SMP
-	long		last_rs_qlen;	 /* qlen during the last resched */
-#endif
 };
 
 DECLARE_PER_CPU(struct rcu_data, rcu_data);
diff --git a/include/linux/scx200.h b/include/linux/scx200.h
index 693c055..de466e1 100644
--- a/include/linux/scx200.h
+++ b/include/linux/scx200.h
@@ -32,7 +32,7 @@
 
 /* High Resolution Timer */
 #define SCx200_TIMER_OFFSET 0x08
-#define SCx200_TIMER_SIZE 0x05
+#define SCx200_TIMER_SIZE 0x06
 
 /* Clock Generators */
 #define SCx200_CLOCKGEN_OFFSET 0x10
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index de2e681..b661c19 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -67,8 +67,8 @@
 /* Parisc type numbers. */
 #define PORT_MUX	48
 
-/* Atmel AT91xxx SoC */
-#define PORT_AT91	49
+/* Atmel AT91 / AT32 SoC */
+#define PORT_ATMEL	49
 
 /* Macintosh Zilog type numbers */
 #define PORT_MAC_ZILOG	50	/* m68k : not yet implemented */
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 70be57d..c4947b8 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -77,13 +77,6 @@
 extern struct cache_sizes malloc_sizes[];
 
 extern void *__kmalloc(size_t, gfp_t);
-#ifndef CONFIG_DEBUG_SLAB
-#define ____kmalloc(size, flags) __kmalloc(size, flags)
-#else
-extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
-#define ____kmalloc(size, flags) \
-    __kmalloc_track_caller(size, flags, __builtin_return_address(0))
-#endif
 
 /**
  * kmalloc - allocate memory
@@ -153,6 +146,23 @@
 	return __kmalloc(size, flags);
 }
 
+/*
+ * kmalloc_track_caller is a special version of kmalloc that records the
+ * calling function of the routine calling it for slab leak tracking instead
+ * of just the calling function (confusing, eh?).
+ * It's useful when the call to kmalloc comes from a widely-used standard
+ * allocator where we care about the real place the memory allocation
+ * request comes from.
+ */
+#ifndef CONFIG_DEBUG_SLAB
+#define kmalloc_track_caller(size, flags) \
+	__kmalloc(size, flags)
+#else
+extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
+#define kmalloc_track_caller(size, flags) \
+	__kmalloc_track_caller(size, flags, __builtin_return_address(0))
+#endif
+
 extern void *__kzalloc(size_t, gfp_t);
 
 /**
@@ -271,7 +281,7 @@
 #define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f)
 #define kmalloc_node(s, f, n) kmalloc(s, f)
 #define kzalloc(s, f) __kzalloc(s, f)
-#define ____kmalloc kmalloc
+#define kmalloc_track_caller kmalloc
 
 #endif /* CONFIG_SLOB */
 
diff --git a/include/linux/sound.h b/include/linux/sound.h
index f63d834..9e2a94f 100644
--- a/include/linux/sound.h
+++ b/include/linux/sound.h
@@ -35,10 +35,8 @@
 extern int register_sound_mixer(const struct file_operations *fops, int dev);
 extern int register_sound_midi(const struct file_operations *fops, int dev);
 extern int register_sound_dsp(const struct file_operations *fops, int dev);
-extern int register_sound_synth(const struct file_operations *fops, int dev);
 
 extern void unregister_sound_special(int unit);
 extern void unregister_sound_mixer(int unit);
 extern void unregister_sound_midi(int unit);
 extern void unregister_sound_dsp(int unit);
-extern void unregister_sound_synth(int unit);
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
new file mode 100644
index 0000000..aca0eee
--- /dev/null
+++ b/include/linux/srcu.h
@@ -0,0 +1,53 @@
+/*
+ * Sleepable Read-Copy Update mechanism for mutual exclusion
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Paul McKenney <paulmck@us.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * 		Documentation/RCU/ *.txt
+ *
+ */
+
+#ifndef _LINUX_SRCU_H
+#define _LINUX_SRCU_H
+
+struct srcu_struct_array {
+	int c[2];
+};
+
+struct srcu_struct {
+	int completed;
+	struct srcu_struct_array *per_cpu_ref;
+	struct mutex mutex;
+};
+
+#ifndef CONFIG_PREEMPT
+#define srcu_barrier() barrier()
+#else /* #ifndef CONFIG_PREEMPT */
+#define srcu_barrier()
+#endif /* #else #ifndef CONFIG_PREEMPT */
+
+int init_srcu_struct(struct srcu_struct *sp);
+void cleanup_srcu_struct(struct srcu_struct *sp);
+int srcu_read_lock(struct srcu_struct *sp) __acquires(sp);
+void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp);
+void synchronize_srcu(struct srcu_struct *sp);
+long srcu_batches_completed(struct srcu_struct *sp);
+
+#endif
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 862c0d8c..534cdc7 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -20,9 +20,6 @@
 /* size of the nodename buffer */
 #define UNX_MAXNODENAME	32
 
-/* Maximum size (in bytes) of an rpc credential or verifier */
-#define RPC_MAX_AUTH_SIZE (400)
-
 /* Work around the lack of a VFS credential */
 struct auth_cred {
 	uid_t	uid;
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index b5612c9..3699dff 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -163,6 +163,17 @@
 	kref_put(&h->ref, cd->cache_put);
 }
 
+static inline int cache_valid(struct cache_head *h)
+{
+	/* If an item has been unhashed pending removal when
+	 * the refcount drops to 0, the expiry_time will be
+	 * set to 0.  We don't want to consider such items
+	 * valid in this context even though CACHE_VALID is
+	 * set.
+	 */
+	return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags));
+}
+
 extern int cache_check(struct cache_detail *detail,
 		       struct cache_head *h, struct cache_req *rqstp);
 extern void cache_flush(void);
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index 8d10d14..1e65f2d 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -11,6 +11,9 @@
 
 #define RPC_VERSION 2
 
+/* size of an XDR encoding unit in bytes, i.e. 32bit */
+#define XDR_UNIT	(4)
+
 /* spec defines authentication flavor as an unsigned 32 bit integer */
 typedef u32	rpc_authflavor_t;
 
@@ -34,6 +37,9 @@
 	RPC_AUTH_GSS_SPKMP = 390011,
 };
 
+/* Maximum size (in bytes) of an rpc credential or verifier */
+#define RPC_MAX_AUTH_SIZE (400)
+
 enum rpc_msg_type {
 	RPC_CALL = 0,
 	RPC_REPLY = 1
@@ -101,5 +107,39 @@
 #define	RPC_FRAGMENT_SIZE_MASK		(~RPC_LAST_STREAM_FRAGMENT)
 #define	RPC_MAX_FRAGMENT_SIZE		((1U << 31) - 1)
 
+/*
+ * RPC call and reply header size as number of 32bit words (verifier
+ * size computed separately, see below)
+ */
+#define RPC_CALLHDRSIZE		(6)
+#define RPC_REPHDRSIZE		(4)
+
+
+/*
+ * Maximum RPC header size, including authentication,
+ * as number of 32bit words (see RFCs 1831, 1832).
+ *
+ *	xid			    1 xdr unit = 4 bytes
+ *	mtype			    1
+ *	rpc_version		    1
+ *	program			    1
+ *	prog_version		    1
+ *	procedure		    1
+ *	cred {
+ *	    flavor		    1
+ *	    length		    1
+ *	    body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
+ *	}
+ *	verf {
+ *	    flavor		    1
+ *	    length		    1
+ *	    body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
+ *	}
+ *	TOTAL			    210 xdr units = 840 bytes
+ */
+#define RPC_MAX_HEADER_WITH_AUTH \
+	(RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
+
+
 #endif /* __KERNEL__ */
 #endif /* _LINUX_SUNRPC_MSGPROT_H_ */
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 4ebcdf9..d6288e8 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -13,6 +13,7 @@
 #include <linux/in.h>
 #include <linux/sunrpc/types.h>
 #include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/svcauth.h>
 #include <linux/wait.h>
 #include <linux/mm.h>
@@ -95,8 +96,28 @@
  * Maximum payload size supported by a kernel RPC server.
  * This is use to determine the max number of pages nfsd is
  * willing to return in a single READ operation.
+ *
+ * These happen to all be powers of 2, which is not strictly
+ * necessary but helps enforce the real limitation, which is
+ * that they should be multiples of PAGE_CACHE_SIZE.
+ *
+ * For UDP transports, a block plus NFS,RPC, and UDP headers
+ * has to fit into the IP datagram limit of 64K.  The largest
+ * feasible number for all known page sizes is probably 48K,
+ * but we choose 32K here.  This is the same as the historical
+ * Linux limit; someone who cares more about NFS/UDP performance
+ * can test a larger number.
+ *
+ * For TCP transports we have more freedom.  A size of 1MB is
+ * chosen to match the client limit.  Other OSes are known to
+ * have larger limits, but those numbers are probably beyond
+ * the point of diminishing returns.
  */
-#define RPCSVC_MAXPAYLOAD	(64*1024u)
+#define RPCSVC_MAXPAYLOAD	(1*1024*1024u)
+#define RPCSVC_MAXPAYLOAD_TCP	RPCSVC_MAXPAYLOAD
+#define RPCSVC_MAXPAYLOAD_UDP	(32*1024u)
+
+extern u32 svc_max_payload(const struct svc_rqst *rqstp);
 
 /*
  * RPC Requsts and replies are stored in one or more pages.
@@ -170,7 +191,6 @@
 /*
  * The context of a single thread, including the request currently being
  * processed.
- * NOTE: First two items must be prev/next.
  */
 struct svc_rqst {
 	struct list_head	rq_list;	/* idle list */
@@ -189,12 +209,11 @@
 
 	struct xdr_buf		rq_arg;
 	struct xdr_buf		rq_res;
-	struct page *		rq_argpages[RPCSVC_MAXPAGES];
-	struct page *		rq_respages[RPCSVC_MAXPAGES];
-	int			rq_restailpage;
-	short			rq_argused;	/* pages used for argument */
-	short			rq_arghi;	/* pages available in argument page list */
-	short			rq_resused;	/* pages used for result */
+	struct page *		rq_pages[RPCSVC_MAXPAGES];
+	struct page *		*rq_respages;	/* points into rq_pages */
+	int			rq_resused;	/* number of pages used for result */
+
+	struct kvec		rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
 
 	__be32			rq_xid;		/* transmission id */
 	u32			rq_prog;	/* program number */
@@ -255,63 +274,18 @@
 	return vec->iov_len <= PAGE_SIZE;
 }
 
-static inline struct page *
-svc_take_res_page(struct svc_rqst *rqstp)
+static inline void svc_free_res_pages(struct svc_rqst *rqstp)
 {
-	if (rqstp->rq_arghi <= rqstp->rq_argused)
-		return NULL;
-	rqstp->rq_arghi--;
-	rqstp->rq_respages[rqstp->rq_resused] =
-		rqstp->rq_argpages[rqstp->rq_arghi];
-	return rqstp->rq_respages[rqstp->rq_resused++];
-}
-
-static inline void svc_take_page(struct svc_rqst *rqstp)
-{
-	if (rqstp->rq_arghi <= rqstp->rq_argused) {
-		WARN_ON(1);
-		return;
-	}
-	rqstp->rq_arghi--;
-	rqstp->rq_respages[rqstp->rq_resused] =
-		rqstp->rq_argpages[rqstp->rq_arghi];
-	rqstp->rq_resused++;
-}
-
-static inline void svc_pushback_allpages(struct svc_rqst *rqstp)
-{
-        while (rqstp->rq_resused) {
-		if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
-			continue;
-		rqstp->rq_argpages[rqstp->rq_arghi++] =
-			rqstp->rq_respages[rqstp->rq_resused];
-		rqstp->rq_respages[rqstp->rq_resused] = NULL;
-	}
-}
-
-static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp)
-{
-	while (rqstp->rq_resused &&
-	       rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) {
-
-		if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) {
-			rqstp->rq_argpages[rqstp->rq_arghi++] =
-				rqstp->rq_respages[rqstp->rq_resused];
-			rqstp->rq_respages[rqstp->rq_resused] = NULL;
+	while (rqstp->rq_resused) {
+		struct page **pp = (rqstp->rq_respages +
+				    --rqstp->rq_resused);
+		if (*pp) {
+			put_page(*pp);
+			*pp = NULL;
 		}
 	}
 }
 
-static inline void svc_free_allpages(struct svc_rqst *rqstp)
-{
-        while (rqstp->rq_resused) {
-		if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
-			continue;
-		put_page(rqstp->rq_respages[rqstp->rq_resused]);
-		rqstp->rq_respages[rqstp->rq_resused] = NULL;
-	}
-}
-
 struct svc_deferred_req {
 	u32			prot;	/* protocol (UDP or TCP) */
 	struct sockaddr_in	addr;
@@ -347,6 +321,9 @@
 	struct svc_procedure *	vs_proc;	/* per-procedure info */
 	u32			vs_xdrsize;	/* xdrsize needed for this version */
 
+	unsigned int		vs_hidden : 1;	/* Don't register with portmapper.
+						 * Only used for nfsacl so far. */
+
 	/* Override dispatch function (e.g. when caching replies).
 	 * A return value of 0 means drop the request. 
 	 * vs_dispatch == NULL means use default dispatcher.
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index a660165..de92619 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -126,6 +126,7 @@
 extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
 extern int auth_unix_forget_old(struct auth_domain *dom);
 extern void svcauth_unix_purge(void);
+extern void svcauth_unix_info_release(void *);
 
 static inline unsigned long hash_str(char *name, int bits)
 {
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 4c29615..98b21ad 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -54,6 +54,9 @@
 	int			sk_reclen;	/* length of record */
 	int			sk_tcplen;	/* current read length */
 	time_t			sk_lastrecv;	/* time of last received request */
+
+	/* cache of various info for TCP sockets */
+	void			*sk_info_authunix;
 };
 
 /*
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 6cf6265..60394fb 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -15,6 +15,7 @@
 #include <linux/kref.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/msg_prot.h>
 
 extern unsigned int xprt_udp_slot_table_entries;
 extern unsigned int xprt_tcp_slot_table_entries;
@@ -24,13 +25,6 @@
 #define RPC_MAX_SLOT_TABLE	(128U)
 
 /*
- * RPC call and reply header size as number of 32bit words (verifier
- * size computed separately)
- */
-#define RPC_CALLHDRSIZE		6
-#define RPC_REPHDRSIZE		4
-
-/*
  * Parameters for choosing a free port
  */
 extern unsigned int xprt_min_resvport;
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
new file mode 100644
index 0000000..203dd5e
--- /dev/null
+++ b/include/linux/tifm.h
@@ -0,0 +1,158 @@
+/*
+ *  tifm.h - TI FlashMedia driver
+ *
+ *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.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
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _TIFM_H
+#define _TIFM_H
+
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+/* Host registers (relative to pci base address): */
+enum {
+	FM_SET_INTERRUPT_ENABLE   = 0x008,
+	FM_CLEAR_INTERRUPT_ENABLE = 0x00c,
+	FM_INTERRUPT_STATUS       = 0x014 };
+
+/* Socket registers (relative to socket base address): */
+enum {
+	SOCK_CONTROL                   = 0x004,
+	SOCK_PRESENT_STATE             = 0x008,
+	SOCK_DMA_ADDRESS               = 0x00c,
+	SOCK_DMA_CONTROL               = 0x010,
+	SOCK_DMA_FIFO_INT_ENABLE_SET   = 0x014,
+	SOCK_DMA_FIFO_INT_ENABLE_CLEAR = 0x018,
+	SOCK_DMA_FIFO_STATUS           = 0x020,
+	SOCK_FIFO_CONTROL              = 0x024,
+	SOCK_FIFO_PAGE_SIZE            = 0x028,
+	SOCK_MMCSD_COMMAND             = 0x104,
+	SOCK_MMCSD_ARG_LOW             = 0x108,
+	SOCK_MMCSD_ARG_HIGH            = 0x10c,
+	SOCK_MMCSD_CONFIG              = 0x110,
+	SOCK_MMCSD_STATUS              = 0x114,
+	SOCK_MMCSD_INT_ENABLE          = 0x118,
+	SOCK_MMCSD_COMMAND_TO          = 0x11c,
+	SOCK_MMCSD_DATA_TO             = 0x120,
+	SOCK_MMCSD_DATA                = 0x124,
+	SOCK_MMCSD_BLOCK_LEN           = 0x128,
+	SOCK_MMCSD_NUM_BLOCKS          = 0x12c,
+	SOCK_MMCSD_BUFFER_CONFIG       = 0x130,
+	SOCK_MMCSD_SPI_CONFIG          = 0x134,
+	SOCK_MMCSD_SDIO_MODE_CONFIG    = 0x138,
+	SOCK_MMCSD_RESPONSE            = 0x144,
+	SOCK_MMCSD_SDIO_SR             = 0x164,
+	SOCK_MMCSD_SYSTEM_CONTROL      = 0x168,
+	SOCK_MMCSD_SYSTEM_STATUS       = 0x16c,
+	SOCK_MS_COMMAND                = 0x184,
+	SOCK_MS_DATA                   = 0x188,
+	SOCK_MS_STATUS                 = 0x18c,
+	SOCK_MS_SYSTEM                 = 0x190,
+	SOCK_FIFO_ACCESS               = 0x200 };
+
+
+#define TIFM_IRQ_ENABLE           0x80000000
+#define TIFM_IRQ_SOCKMASK         0x00000001
+#define TIFM_IRQ_CARDMASK         0x00000100
+#define TIFM_IRQ_FIFOMASK         0x00010000
+#define TIFM_IRQ_SETALL           0xffffffff
+#define TIFM_IRQ_SETALLSOCK       0x0000000f
+
+#define TIFM_CTRL_LED             0x00000040
+#define TIFM_CTRL_FAST_CLK        0x00000100
+
+#define TIFM_SOCK_STATE_OCCUPIED  0x00000008
+#define TIFM_SOCK_STATE_POWERED   0x00000080
+
+#define TIFM_FIFO_ENABLE          0x00000001 /* Meaning of this constant is unverified */
+#define TIFM_FIFO_INT_SETALL      0x0000ffff
+#define TIFM_FIFO_INTMASK         0x00000005 /* Meaning of this constant is unverified */
+
+#define TIFM_DMA_RESET            0x00000002 /* Meaning of this constant is unverified */
+#define TIFM_DMA_TX               0x00008000 /* Meaning of this constant is unverified */
+#define TIFM_DMA_EN               0x00000001 /* Meaning of this constant is unverified */
+
+typedef enum {FM_NULL = 0, FM_XD = 0x01, FM_MS = 0x02, FM_SD = 0x03} tifm_media_id;
+
+struct tifm_driver;
+struct tifm_dev {
+	char __iomem            *addr;
+	spinlock_t              lock;
+	tifm_media_id           media_id;
+	char                    wq_name[KOBJ_NAME_LEN];
+	struct workqueue_struct *wq;
+
+	unsigned int            (*signal_irq)(struct tifm_dev *sock,
+					      unsigned int sock_irq_status);
+
+	struct tifm_driver      *drv;
+	struct device           dev;
+};
+
+struct tifm_driver {
+	tifm_media_id        *id_table;
+	int                  (*probe)(struct tifm_dev *dev);
+	void                 (*remove)(struct tifm_dev *dev);
+
+	struct device_driver driver;
+};
+
+struct tifm_adapter {
+	char __iomem            *addr;
+	unsigned int            irq_status;
+	unsigned int            insert_mask;
+	unsigned int            remove_mask;
+	spinlock_t              lock;
+	unsigned int            id;
+	unsigned int            max_sockets;
+	char                    wq_name[KOBJ_NAME_LEN];
+	unsigned int            inhibit_new_cards;
+	struct workqueue_struct *wq;
+	struct work_struct      media_inserter;
+	struct work_struct      media_remover;
+	struct tifm_dev         **sockets;
+	struct class_device     cdev;
+	struct device           *dev;
+
+	void                    (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock);
+};
+
+struct tifm_adapter *tifm_alloc_adapter(void);
+void tifm_free_device(struct device *dev);
+void tifm_free_adapter(struct tifm_adapter *fm);
+int tifm_add_adapter(struct tifm_adapter *fm);
+void tifm_remove_adapter(struct tifm_adapter *fm);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id);
+int tifm_register_driver(struct tifm_driver *drv);
+void tifm_unregister_driver(struct tifm_driver *drv);
+void tifm_eject(struct tifm_dev *sock);
+int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+		int direction);
+void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+		   int direction);
+
+
+static inline void *tifm_get_drvdata(struct tifm_dev *dev)
+{
+        return dev_get_drvdata(&dev->dev);
+}
+
+static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data)
+{
+	dev_set_drvdata(&dev->dev, data);
+}
+
+struct tifm_device_id {
+	tifm_media_id media_id;
+};
+
+#endif
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index 02e4b69..a4555fe 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -1,11 +1,6 @@
 #ifndef _LINUX_UTSNAME_H
 #define _LINUX_UTSNAME_H
 
-#include <linux/sched.h>
-#include <linux/kref.h>
-#include <linux/nsproxy.h>
-#include <asm/atomic.h>
-
 #define __OLD_UTS_LEN 8
 
 struct oldold_utsname {
@@ -35,6 +30,13 @@
 	char domainname[65];
 };
 
+#ifdef __KERNEL__
+
+#include <linux/sched.h>
+#include <linux/kref.h>
+#include <linux/nsproxy.h>
+#include <asm/atomic.h>
+
 struct uts_namespace {
 	struct kref kref;
 	struct new_utsname name;
@@ -86,4 +88,7 @@
 }
 
 extern struct rw_semaphore uts_sem;
-#endif
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_UTSNAME_H */
diff --git a/include/linux/wavefront.h b/include/linux/wavefront.h
deleted file mode 100644
index 51ab3c9..0000000
--- a/include/linux/wavefront.h
+++ /dev/null
@@ -1,675 +0,0 @@
-#ifndef __wavefront_h__
-#define __wavefront_h__
-
-/* WaveFront header file.
- *   
- * Copyright (C) by Paul Barton-Davis 1998
- *
- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.  
- */
-
-#if (!defined(__GNUC__) && !defined(__GNUG__))
-
-     You will not be able to compile this file correctly without gcc, because
-     it is necessary to pack the "wavefront_alias" structure to a size
-     of 22 bytes, corresponding to 16-bit alignment (as would have been
-     the case on the original platform, MS-DOS). If this is not done,
-     then WavePatch-format files cannot be read/written correctly.
-     The method used to do this here ("__attribute__((packed)") is
-     completely compiler dependent.
-     
-     All other wavefront_* types end up aligned to 32 bit values and
-     still have the same (correct) size.
-
-#else
-
-     /* However, note that as of G++ 2.7.3.2, g++ was unable to
-	correctly parse *type* __attribute__ tags. It will do the
-	right thing if we use the "packed" attribute on each struct
-	member, which has the same semantics anyway. 
-     */
-
-#endif /* __GNUC__ */
-
-/***************************** WARNING ********************************
-  PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO 
-  BE USED WITH EITHER C *OR* C++.
- **********************************************************************/
-
-#ifndef NUM_MIDIKEYS 
-#define NUM_MIDIKEYS 128
-#endif  /* NUM_MIDIKEYS */
-
-#ifndef NUM_MIDICHANNELS
-#define NUM_MIDICHANNELS 16
-#endif  /* NUM_MIDICHANNELS */
-
-/* These are very useful/important. the original wavefront interface
-   was developed on a 16 bit system, where sizeof(int) = 2
-   bytes. Defining things like this makes the code much more portable, and
-   easier to understand without having to toggle back and forth
-   between a 16-bit view of the world and a 32-bit one. 
- */   
-
-typedef short INT16;
-typedef unsigned short UINT16;
-typedef int INT32;
-typedef unsigned int UINT32;
-typedef char CHAR8;
-typedef unsigned char UCHAR8;
-
-/* Pseudo-commands not part of the WaveFront command set.
-   These are used for various driver controls and direct
-   hardware control.
- */
-
-#define WFC_DEBUG_DRIVER                0
-#define WFC_FX_IOCTL                    1
-#define WFC_PATCH_STATUS                2
-#define WFC_PROGRAM_STATUS              3
-#define WFC_SAMPLE_STATUS               4
-#define WFC_DISABLE_INTERRUPTS          5
-#define WFC_ENABLE_INTERRUPTS           6
-#define WFC_INTERRUPT_STATUS            7
-#define WFC_ROMSAMPLES_RDONLY           8
-#define WFC_IDENTIFY_SLOT_TYPE          9
-
-/* Wavefront synth commands
- */
-
-#define WFC_DOWNLOAD_SAMPLE		0x80
-#define WFC_DOWNLOAD_BLOCK		0x81
-#define WFC_DOWNLOAD_MULTISAMPLE	0x82
-#define WFC_DOWNLOAD_SAMPLE_ALIAS	0x83
-#define WFC_DELETE_SAMPLE		0x84
-#define WFC_REPORT_FREE_MEMORY		0x85
-#define WFC_DOWNLOAD_PATCH		0x86
-#define WFC_DOWNLOAD_PROGRAM		0x87
-#define WFC_SET_SYNTHVOL		0x89
-#define WFC_SET_NVOICES			0x8B
-#define WFC_DOWNLOAD_DRUM		0x90
-#define WFC_GET_SYNTHVOL		0x92
-#define WFC_GET_NVOICES			0x94
-#define WFC_DISABLE_CHANNEL		0x9A
-#define WFC_ENABLE_CHANNEL		0x9B
-#define WFC_MISYNTH_OFF			0x9D
-#define WFC_MISYNTH_ON			0x9E
-#define WFC_FIRMWARE_VERSION		0x9F
-#define WFC_GET_NSAMPLES		0xA0
-#define WFC_DISABLE_DRUM_PROGRAM	0xA2
-#define WFC_UPLOAD_PATCH		0xA3
-#define WFC_UPLOAD_PROGRAM		0xA4
-#define WFC_SET_TUNING			0xA6
-#define WFC_GET_TUNING			0xA7
-#define WFC_VMIDI_ON			0xA8
-#define WFC_VMIDI_OFF			0xA9
-#define WFC_MIDI_STATUS			0xAA
-#define WFC_GET_CHANNEL_STATUS		0xAB
-#define WFC_DOWNLOAD_SAMPLE_HEADER	0xAC
-#define WFC_UPLOAD_SAMPLE_HEADER	0xAD
-#define WFC_UPLOAD_MULTISAMPLE		0xAE
-#define WFC_UPLOAD_SAMPLE_ALIAS		0xAF
-#define WFC_IDENTIFY_SAMPLE_TYPE	0xB0
-#define WFC_DOWNLOAD_EDRUM_PROGRAM	0xB1
-#define WFC_UPLOAD_EDRUM_PROGRAM	0xB2
-#define WFC_SET_EDRUM_CHANNEL		0xB3
-#define WFC_INSTOUT_LEVELS		0xB4
-#define WFC_PEAKOUT_LEVELS		0xB5
-#define WFC_REPORT_CHANNEL_PROGRAMS	0xB6
-#define WFC_HARDWARE_VERSION		0xCF
-#define WFC_UPLOAD_SAMPLE_PARAMS	0xD7
-#define WFC_DOWNLOAD_OS			0xF1
-#define WFC_NOOP                        0xFF
-
-#define WF_MAX_SAMPLE   512
-#define WF_MAX_PATCH    256
-#define WF_MAX_PROGRAM  128
-
-#define WF_SECTION_MAX  44   /* longest OS section length */
-
-/* # of bytes we send to the board when sending it various kinds of
-   substantive data, such as samples, patches and programs.
-*/
-
-#define WF_PROGRAM_BYTES 32
-#define WF_PATCH_BYTES 132
-#define WF_SAMPLE_BYTES 27
-#define WF_SAMPLE_HDR_BYTES 25
-#define WF_ALIAS_BYTES 25
-#define WF_DRUM_BYTES 9
-#define WF_MSAMPLE_BYTES 259 /* (MIDI_KEYS * 2) + 3 */
-
-#define WF_ACK     0x80
-#define WF_DMA_ACK 0x81
-
-/* OR-values for MIDI status bits */
-
-#define WF_MIDI_VIRTUAL_ENABLED 0x1
-#define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2
-#define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4
-
-/* slot indexes for struct address_info: makes code a little more mnemonic */
-
-#define WF_SYNTH_SLOT         0
-#define WF_INTERNAL_MIDI_SLOT 1
-#define WF_EXTERNAL_MIDI_SLOT 2
-
-/* Magic MIDI bytes used to switch I/O streams on the ICS2115 MPU401
-   emulation. Note these NEVER show up in output from the device and
-   should NEVER be used in input unless Virtual MIDI mode has been 
-   disabled. If they do show up as input, the results are unpredictable.
-*/
-
-#define WF_EXTERNAL_SWITCH  0xFD
-#define WF_INTERNAL_SWITCH  0xF9
-
-/* Debugging flags */
-
-#define WF_DEBUG_CMD 0x1
-#define WF_DEBUG_DATA 0x2
-#define WF_DEBUG_LOAD_PATCH 0x4
-#define WF_DEBUG_IO 0x8
-
-/* WavePatch file format stuff */
-
-#define WF_WAVEPATCH_VERSION     120;  /*  Current version number (1.2)  */
-#define WF_MAX_COMMENT           64    /*  Comment length */
-#define WF_NUM_LAYERS            4
-#define WF_NAME_LENGTH           32
-#define WF_SOURCE_LENGTH         260
-
-#define BankFileID     "Bank"
-#define DrumkitFileID  "DrumKit"
-#define ProgramFileID  "Program"
-
-struct wf_envelope
-{
-    UCHAR8 attack_time:7;
-    UCHAR8 Unused1:1;
-
-    UCHAR8 decay1_time:7;
-    UCHAR8 Unused2:1;
-
-    UCHAR8 decay2_time:7;
-    UCHAR8 Unused3:1;
-
-    UCHAR8 sustain_time:7;
-    UCHAR8 Unused4:1;
-
-    UCHAR8 release_time:7;
-    UCHAR8 Unused5:1;
-
-    UCHAR8 release2_time:7;
-    UCHAR8 Unused6:1;
-
-    CHAR8 attack_level;
-    CHAR8 decay1_level;
-    CHAR8 decay2_level;
-    CHAR8 sustain_level;
-    CHAR8 release_level;
-
-    UCHAR8 attack_velocity:7;
-    UCHAR8 Unused7:1;
-
-    UCHAR8 volume_velocity:7;
-    UCHAR8 Unused8:1;
-
-    UCHAR8 keyboard_scaling:7;
-    UCHAR8 Unused9:1;
-};
-typedef struct wf_envelope wavefront_envelope;
-
-struct wf_lfo
-{
-    UCHAR8 sample_number;
-
-    UCHAR8 frequency:7;
-    UCHAR8 Unused1:1;
-
-    UCHAR8 am_src:4;
-    UCHAR8 fm_src:4;
-
-    CHAR8 fm_amount;
-    CHAR8 am_amount;
-    CHAR8 start_level;
-    CHAR8 end_level;
-
-    UCHAR8 ramp_delay:7;
-    UCHAR8 wave_restart:1; /* for LFO2 only */
-
-    UCHAR8 ramp_time:7;
-    UCHAR8 Unused2:1;
-};
-typedef struct wf_lfo wavefront_lfo;
-
-struct wf_patch
-{
-    INT16  frequency_bias;         /*  ** THIS IS IN MOTOROLA FORMAT!! ** */
-
-    UCHAR8 amplitude_bias:7;
-    UCHAR8 Unused1:1;
-
-    UCHAR8 portamento:7;
-    UCHAR8 Unused2:1;
-
-    UCHAR8 sample_number;
-
-    UCHAR8 pitch_bend:4;
-    UCHAR8 sample_msb:1;
-    UCHAR8 Unused3:3;
-
-    UCHAR8 mono:1;
-    UCHAR8 retrigger:1;
-    UCHAR8 nohold:1;
-    UCHAR8 restart:1;
-    UCHAR8 filterconfig:2; /* SDK says "not used" */
-    UCHAR8 reuse:1;
-    UCHAR8 reset_lfo:1;    
-
-    UCHAR8 fm_src2:4;
-    UCHAR8 fm_src1:4;   
-
-    CHAR8 fm_amount1;
-    CHAR8 fm_amount2;
-
-    UCHAR8 am_src:4;
-    UCHAR8 Unused4:4;
-
-    CHAR8 am_amount;
-
-    UCHAR8 fc1_mode:4;
-    UCHAR8 fc2_mode:4;
-
-    CHAR8 fc1_mod_amount;
-    CHAR8 fc1_keyboard_scaling;
-    CHAR8 fc1_bias;
-    CHAR8 fc2_mod_amount;
-    CHAR8 fc2_keyboard_scaling;
-    CHAR8 fc2_bias;
-
-    UCHAR8 randomizer:7;
-    UCHAR8 Unused5:1;
-
-    struct wf_envelope envelope1;
-    struct wf_envelope envelope2;
-    struct wf_lfo lfo1;
-    struct wf_lfo lfo2;
-};
-typedef struct wf_patch wavefront_patch;
-
-struct wf_layer
-{
-    UCHAR8 patch_number;
-
-    UCHAR8 mix_level:7;
-    UCHAR8 mute:1;
-
-    UCHAR8 split_point:7;
-    UCHAR8 play_below:1;
-
-    UCHAR8 pan_mod_src:2;
-    UCHAR8 pan_or_mod:1;
-    UCHAR8 pan:4;
-    UCHAR8 split_type:1;
-};
-typedef struct wf_layer wavefront_layer;
-
-struct wf_program
-{
-    struct wf_layer layer[WF_NUM_LAYERS];
-};
-typedef struct wf_program wavefront_program;
-
-struct wf_sample_offset
-{
-    INT32 Fraction:4;
-    INT32 Integer:20;
-    INT32 Unused:8;
-};
-typedef struct wf_sample_offset wavefront_sample_offset;          
-     
-/* Sample slot types */
-
-#define WF_ST_SAMPLE      0
-#define WF_ST_MULTISAMPLE 1
-#define WF_ST_ALIAS       2
-#define WF_ST_EMPTY       3
-
-/* pseudo's */
-
-#define WF_ST_DRUM        4
-#define WF_ST_PROGRAM     5
-#define WF_ST_PATCH       6
-#define WF_ST_SAMPLEHDR   7
-
-#define WF_ST_MASK        0xf
-
-/* Flags for slot status. These occupy the upper bits of the same byte
-   as a sample type.
-*/
-
-#define WF_SLOT_USED      0x80   /* XXX don't rely on this being accurate */
-#define WF_SLOT_FILLED    0x40
-#define WF_SLOT_ROM       0x20
-
-#define WF_SLOT_MASK      0xf0
-
-/* channel constants */
-
-#define WF_CH_MONO  0
-#define WF_CH_LEFT  1
-#define WF_CH_RIGHT 2
-
-/* Sample formats */
-
-#define LINEAR_16BIT 0
-#define WHITE_NOISE  1
-#define LINEAR_8BIT  2
-#define MULAW_8BIT   3
-
-#define WF_SAMPLE_IS_8BIT(smpl) ((smpl)->SampleResolution&2)
-
-
-/* 
-
-  Because most/all of the sample data we pass in via pointers has
-  never been copied (just mmap-ed into user space straight from the
-  disk), it would be nice to allow handling of multi-channel sample
-  data without forcing user-level extraction of the relevant bytes.
-  
-  So, we need a way of specifying which channel to use (the WaveFront
-  only handles mono samples in a given slot), and the only way to do
-  this without using some struct other than wavefront_sample as the
-  interface is the awful hack of using the unused bits in a
-  wavefront_sample:
-  
-  Val      Meaning
-  ---      -------
-  0        no channel selection (use channel 1, sample is MONO)
-  1        use first channel, and skip one
-  2        use second channel, and skip one
-  3        use third channel, and skip two
-  4        use fourth channel, skip three
-  5        use fifth channel, skip four
-  6        use six channel, skip five
-
-
-  This can handle up to 4 channels, and anyone downloading >4 channels
-  of sample data just to select one of them needs to find some tools
-  like sox ...
-
-  NOTE: values 0, 1 and 2 correspond to WF_CH_* above. This is 
-  important.
-
-*/
-
-#define WF_SET_CHANNEL(samp,chn) \
- (samp)->Unused1 = chn & 0x1; \
- (samp)->Unused2 = chn & 0x2; \
- (samp)->Unused3 = chn & 0x4 
-  
-#define WF_GET_CHANNEL(samp) \
-  (((samp)->Unused3 << 2)|((samp)->Unused2<<1)|(samp)->Unused1)
-  
-typedef struct wf_sample {
-    struct wf_sample_offset sampleStartOffset;
-    struct wf_sample_offset loopStartOffset;
-    struct wf_sample_offset loopEndOffset;
-    struct wf_sample_offset sampleEndOffset;
-    INT16 FrequencyBias;
-    UCHAR8 SampleResolution:2;  /* sample_format */
-    UCHAR8 Unused1:1;
-    UCHAR8 Loop:1;
-    UCHAR8 Bidirectional:1;
-    UCHAR8 Unused2:1;
-    UCHAR8 Reverse:1;
-    UCHAR8 Unused3:1;
-} wavefront_sample;
-
-typedef struct wf_multisample {
-    INT16 NumberOfSamples;   /* log2 of the number of samples */
-    INT16 SampleNumber[NUM_MIDIKEYS];
-} wavefront_multisample;
-
-typedef struct wf_alias {
-    INT16 OriginalSample;
-
-    struct wf_sample_offset sampleStartOffset;
-    struct wf_sample_offset loopStartOffset;
-    struct wf_sample_offset sampleEndOffset;
-    struct wf_sample_offset loopEndOffset;
-
-    INT16  FrequencyBias;
-
-    UCHAR8 SampleResolution:2;
-    UCHAR8 Unused1:1;
-    UCHAR8 Loop:1;
-    UCHAR8 Bidirectional:1;
-    UCHAR8 Unused2:1;
-    UCHAR8 Reverse:1;
-    UCHAR8 Unused3:1;
-    
-    /* This structure is meant to be padded only to 16 bits on their
-       original. Of course, whoever wrote their documentation didn't
-       realize that sizeof(struct) can be >=
-       sum(sizeof(struct-fields)) and so thought that giving a C level
-       description of the structs used in WavePatch files was
-       sufficient. I suppose it was, as long as you remember the 
-       standard 16->32 bit issues.
-    */
-
-    UCHAR8 sixteen_bit_padding;
-} __attribute__((packed)) wavefront_alias;
-
-typedef struct wf_drum {
-    UCHAR8 PatchNumber;
-    UCHAR8 MixLevel:7;
-    UCHAR8 Unmute:1;
-    UCHAR8 Group:4;
-    UCHAR8 Unused1:4;
-    UCHAR8 PanModSource:2;
-    UCHAR8 PanModulated:1;
-    UCHAR8 PanAmount:4;
-    UCHAR8 Unused2:1;
-} wavefront_drum;
-
-typedef struct wf_drumkit {
-    struct wf_drum drum[NUM_MIDIKEYS];
-} wavefront_drumkit;
-
-typedef struct wf_channel_programs {
-    UCHAR8 Program[NUM_MIDICHANNELS];
-} wavefront_channel_programs;
-
-/* How to get MIDI channel status from the data returned by
-   a WFC_GET_CHANNEL_STATUS command (a struct wf_channel_programs)
-*/
-
-#define WF_CHANNEL_STATUS(ch,wcp) (wcp)[(ch/7)] & (1<<((ch)%7))
-
-typedef union wf_any {
-    wavefront_sample s;
-    wavefront_multisample ms;
-    wavefront_alias a;
-    wavefront_program pr;
-    wavefront_patch p;
-    wavefront_drum d;
-} wavefront_any;
-
-/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h
-   might work for other wave-table based patch loading situations.
-   Alas, his fears were correct. The WaveFront doesn't even come with
-   just "patches", but several different kind of structures that
-   control the sound generation process.
- */
-
-typedef struct wf_patch_info {
-    
-    /* the first two fields are used by the OSS "patch loading" interface
-       only, and are unused by the current user-level library.
-    */
-
-    INT16   key;               /* Use WAVEFRONT_PATCH here */
-    UINT16  devno;             /* fill in when sending */
-    UCHAR8  subkey;            /* WF_ST_{SAMPLE,ALIAS,etc.} */
-
-#define WAVEFRONT_FIND_FREE_SAMPLE_SLOT 999
-
-    UINT16  number;            /* patch/sample/prog number */
-
-    UINT32  size;              /* size of any data included in 
-				  one of the fields in `hdrptr', or
-				  as `dataptr'.
-
-				  NOTE: for actual samples, this is
-				  the size of the *SELECTED CHANNEL*
-				  even if more data is actually available.
-				  
-				  So, a stereo sample (2 channels) of
-				  6000 bytes total has `size' = 3000.
-
-				  See the macros and comments for
-				  WF_{GET,SET}_CHANNEL above.
-
-			       */
-    wavefront_any __user *hdrptr;      /* user-space ptr to hdr bytes */
-    UINT16 __user *dataptr;            /* actual sample data */
-
-    wavefront_any hdr;          /* kernel-space copy of hdr bytes */         
-} wavefront_patch_info;
-
-/* The maximum number of bytes we will ever move to or from user space
-   in response to a WFC_* command.  This obviously doesn't cover
-   actual sample data.
-*/
-
-#define WF_MAX_READ sizeof(wavefront_multisample)
-#define WF_MAX_WRITE sizeof(wavefront_multisample)
-
-/*
-   This allows us to execute any WF command except the download/upload
-   ones, which are handled differently due to copyin/copyout issues as
-   well as data-nybbling to/from the card.
- */
-
-typedef struct wavefront_control {
-    int cmd;                           /* WFC_* */
-    char status;                       /* return status to user-space */
-    unsigned char rbuf[WF_MAX_READ];   /* bytes read from card */
-    unsigned char wbuf[WF_MAX_WRITE];  /* bytes written to card */
-} wavefront_control;
-
-#define WFCTL_WFCMD    0x1
-#define WFCTL_LOAD_SPP 0x2
-
-/* Modulator table */
-
-#define WF_MOD_LFO1      0
-#define WF_MOD_LFO2      1
-#define WF_MOD_ENV1      2
-#define WF_MOD_ENV2      3
-#define WF_MOD_KEYBOARD  4
-#define WF_MOD_LOGKEY    5
-#define WF_MOD_VELOCITY  6
-#define WF_MOD_LOGVEL    7
-#define WF_MOD_RANDOM    8
-#define WF_MOD_PRESSURE  9
-#define WF_MOD_MOD_WHEEL 10
-#define WF_MOD_1         WF_MOD_MOD_WHEEL 
-#define WF_MOD_BREATH    11
-#define WF_MOD_2         WF_MOD_BREATH
-#define WF_MOD_FOOT      12
-#define WF_MOD_4         WF_MOD_FOOT
-#define WF_MOD_VOLUME    13
-#define WF_MOD_7         WF_MOD_VOLUME
-#define WF_MOD_PAN       14
-#define WF_MOD_10        WF_MOD_PAN
-#define WF_MOD_EXPR      15
-#define WF_MOD_11        WF_MOD_EXPR
-
-/* FX-related material */
-
-typedef struct wf_fx_info {
-    int request;             /* see list below */
-    int data[4];             /* we don't need much */
-} wavefront_fx_info;
-
-/* support for each of these will be forthcoming once I or someone 
-   else has figured out which of the addresses on page 6 and page 7 of 
-   the YSS225 control each parameter. Incidentally, these come from
-   the Windows driver interface, but again, Turtle Beach didn't
-   document the API to use them.
-*/
-
-#define WFFX_SETOUTGAIN		        0
-#define WFFX_SETSTEREOOUTGAIN		1
-#define WFFX_SETREVERBIN1GAIN		2
-#define WFFX_SETREVERBIN2GAIN		3
-#define WFFX_SETREVERBIN3GAIN		4
-#define WFFX_SETCHORUSINPORT		5
-#define WFFX_SETREVERBIN1PORT		6
-#define WFFX_SETREVERBIN2PORT		7
-#define WFFX_SETREVERBIN3PORT		8
-#define WFFX_SETEFFECTPORT		9
-#define WFFX_SETAUXPORT		        10
-#define WFFX_SETREVERBTYPE		11
-#define WFFX_SETREVERBDELAY		12
-#define WFFX_SETCHORUSLFO		13
-#define WFFX_SETCHORUSPMD		14
-#define WFFX_SETCHORUSAMD		15
-#define WFFX_SETEFFECT		        16
-#define WFFX_SETBASEALL		        17
-#define WFFX_SETREVERBALL		18
-#define WFFX_SETCHORUSALL		20
-#define WFFX_SETREVERBDEF		22
-#define WFFX_SETCHORUSDEF		23
-#define WFFX_DELAYSETINGAIN		24
-#define WFFX_DELAYSETFBGAIN	        25
-#define WFFX_DELAYSETFBLPF		26
-#define WFFX_DELAYSETGAIN		27
-#define WFFX_DELAYSETTIME		28
-#define WFFX_DELAYSETFBTIME		29
-#define WFFX_DELAYSETALL		30
-#define WFFX_DELAYSETDEF		32
-#define WFFX_SDELAYSETINGAIN		33
-#define WFFX_SDELAYSETFBGAIN		34
-#define WFFX_SDELAYSETFBLPF		35
-#define WFFX_SDELAYSETGAIN		36
-#define WFFX_SDELAYSETTIME		37
-#define WFFX_SDELAYSETFBTIME		38
-#define WFFX_SDELAYSETALL		39
-#define WFFX_SDELAYSETDEF		41
-#define WFFX_DEQSETINGAIN		42
-#define WFFX_DEQSETFILTER		43
-#define WFFX_DEQSETALL		        44
-#define WFFX_DEQSETDEF		        46
-#define WFFX_MUTE		        47
-#define WFFX_FLANGESETBALANCE	        48	
-#define WFFX_FLANGESETDELAY		49
-#define WFFX_FLANGESETDWFFX_TH		50
-#define WFFX_FLANGESETFBGAIN		51
-#define WFFX_FLANGESETINGAIN		52
-#define WFFX_FLANGESETLFO		53
-#define WFFX_FLANGESETALL		54
-#define WFFX_FLANGESETDEF		56
-#define WFFX_PITCHSETSHIFT		57
-#define WFFX_PITCHSETBALANCE		58
-#define WFFX_PITCHSETALL		59
-#define WFFX_PITCHSETDEF		61
-#define WFFX_SRSSETINGAIN		62
-#define WFFX_SRSSETSPACE		63
-#define WFFX_SRSSETCENTER		64
-#define WFFX_SRSSETGAIN		        65
-#define WFFX_SRSSETMODE	        	66
-#define WFFX_SRSSETDEF		        68
-
-/* Allow direct user-space control over FX memory/coefficient data.
-   In theory this could be used to download the FX microprogram,
-   but it would be a little slower, and involve some weird code.
- */
-
-#define WFFX_MEMSET              69
-
-#endif /* __wavefront_h__ */
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 430afd0..8ae7f74 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -129,7 +129,8 @@
 #define XFRM_MODE_TUNNEL 1
 #define XFRM_MODE_ROUTEOPTIMIZATION 2
 #define XFRM_MODE_IN_TRIGGER 3
-#define XFRM_MODE_MAX 4
+#define XFRM_MODE_BEET 4
+#define XFRM_MODE_MAX 5
 
 /* Netlink configuration messages.  */
 enum {
diff --git a/include/net/netdma.h b/include/net/netdma.h
index 7f53cd1..f28c6e0 100644
--- a/include/net/netdma.h
+++ b/include/net/netdma.h
@@ -20,7 +20,6 @@
  */
 #ifndef NETDMA_H
 #define NETDMA_H
-#include <linux/config.h>
 #ifdef CONFIG_NET_DMA
 #include <linux/dmaengine.h>
 #include <linux/skbuff.h>
diff --git a/init/do_mounts.h b/init/do_mounts.h
index e7f2e7f..735705d 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/syscalls.h>
diff --git a/kernel/Makefile b/kernel/Makefile
index d948ca1..5e3f3b7 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -8,7 +8,7 @@
 	    signal.o sys.o kmod.o workqueue.o pid.o \
 	    rcupdate.o extable.o params.o posix-timers.o \
 	    kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
-	    hrtimer.o rwsem.o latency.o nsproxy.o
+	    hrtimer.o rwsem.o latency.o nsproxy.o srcu.o
 
 obj-$(CONFIG_STACKTRACE) += stacktrace.o
 obj-y += time/
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 1a58a81..4f40d92 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -411,7 +411,6 @@
 		case AUDIT_FSGID:
 		case AUDIT_LOGINUID:
 		case AUDIT_PERS:
-		case AUDIT_ARCH:
 		case AUDIT_MSGTYPE:
 		case AUDIT_PPID:
 		case AUDIT_DEVMAJOR:
@@ -423,6 +422,14 @@
 		case AUDIT_ARG2:
 		case AUDIT_ARG3:
 			break;
+		/* arch is only allowed to be = or != */
+		case AUDIT_ARCH:
+			if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL)
+					&& (f->op != AUDIT_NEGATE) && (f->op)) {
+				err = -EINVAL;
+				goto exit_free;
+			}
+			break;
 		case AUDIT_PERM:
 			if (f->val & ~15)
 				goto exit_free;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 1051476..42f2f11 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -278,8 +278,11 @@
 			result = audit_comparator(tsk->pid, f->op, f->val);
 			break;
 		case AUDIT_PPID:
-			if (ctx)
+			if (ctx) {
+				if (!ctx->ppid)
+					ctx->ppid = sys_getppid();
 				result = audit_comparator(ctx->ppid, f->op, f->val);
+			}
 			break;
 		case AUDIT_UID:
 			result = audit_comparator(tsk->uid, f->op, f->val);
@@ -795,7 +798,8 @@
 
 	/* tsk == current */
 	context->pid = tsk->pid;
-	context->ppid = sys_getppid();	/* sic.  tsk == current in all cases */
+	if (!context->ppid)
+		context->ppid = sys_getppid();
 	context->uid = tsk->uid;
 	context->gid = tsk->gid;
 	context->euid = tsk->euid;
@@ -1137,6 +1141,7 @@
 	context->ctime      = CURRENT_TIME;
 	context->in_syscall = 1;
 	context->auditable  = !!(state == AUDIT_RECORD_CONTEXT);
+	context->ppid       = 0;
 }
 
 /**
@@ -1352,7 +1357,13 @@
 		}
 
 update_context:
-	idx = context->name_count++;
+	idx = context->name_count;
+	if (context->name_count == AUDIT_NAMES) {
+		printk(KERN_DEBUG "name_count maxed and losing %s\n",
+			found_name ?: "(null)");
+		return;
+	}
+	context->name_count++;
 #if AUDIT_DEBUG
 	context->ino_count++;
 #endif
@@ -1370,7 +1381,16 @@
 	/* A parent was not found in audit_names, so copy the inode data for the
 	 * provided parent. */
 	if (!found_name) {
-		idx = context->name_count++;
+		idx = context->name_count;
+		if (context->name_count == AUDIT_NAMES) {
+			printk(KERN_DEBUG
+				"name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu",
+				MAJOR(parent->i_sb->s_dev),
+				MINOR(parent->i_sb->s_dev),
+				parent->i_ino);
+			return;
+		}
+		context->name_count++;
 #if AUDIT_DEBUG
 		context->ino_count++;
 #endif
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 736cb0b..4cf65f5 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -18,6 +18,69 @@
 #include "internals.h"
 
 /**
+ *	dynamic_irq_init - initialize a dynamically allocated irq
+ *	@irq:	irq number to initialize
+ */
+void dynamic_irq_init(unsigned int irq)
+{
+	struct irq_desc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
+		WARN_ON(1);
+		return;
+	}
+
+	/* Ensure we don't have left over values from a previous use of this irq */
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock, flags);
+	desc->status = IRQ_DISABLED;
+	desc->chip = &no_irq_chip;
+	desc->handle_irq = handle_bad_irq;
+	desc->depth = 1;
+	desc->handler_data = NULL;
+	desc->chip_data = NULL;
+	desc->action = NULL;
+	desc->irq_count = 0;
+	desc->irqs_unhandled = 0;
+#ifdef CONFIG_SMP
+	desc->affinity = CPU_MASK_ALL;
+#endif
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ *	dynamic_irq_cleanup - cleanup a dynamically allocated irq
+ *	@irq:	irq number to initialize
+ */
+void dynamic_irq_cleanup(unsigned int irq)
+{
+	struct irq_desc *desc;
+	unsigned long flags;
+
+	if (irq >= NR_IRQS) {
+		printk(KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
+		WARN_ON(1);
+		return;
+	}
+
+	desc = irq_desc + irq;
+	spin_lock_irqsave(&desc->lock, flags);
+	if (desc->action) {
+		spin_unlock_irqrestore(&desc->lock, flags);
+		printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n",
+			irq);
+		WARN_ON(1);
+		return;
+	}
+	desc->handle_irq = handle_bad_irq;
+	desc->chip = &no_irq_chip;
+	spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+
+/**
  *	set_irq_chip - set the irq chip for an irq
  *	@irq:	irq number
  *	@chip:	pointer to irq chip description structure
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
index a57ebe9..4baa3bb 100644
--- a/kernel/irq/migration.c
+++ b/kernel/irq/migration.c
@@ -7,17 +7,17 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&desc->lock, flags);
-	desc->move_irq = 1;
+	desc->status |= IRQ_MOVE_PENDING;
 	irq_desc[irq].pending_mask = mask;
 	spin_unlock_irqrestore(&desc->lock, flags);
 }
 
-void move_native_irq(int irq)
+void move_masked_irq(int irq)
 {
 	struct irq_desc *desc = irq_desc + irq;
 	cpumask_t tmp;
 
-	if (likely(!desc->move_irq))
+	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
 		return;
 
 	/*
@@ -28,7 +28,7 @@
 		return;
 	}
 
-	desc->move_irq = 0;
+	desc->status &= ~IRQ_MOVE_PENDING;
 
 	if (unlikely(cpus_empty(irq_desc[irq].pending_mask)))
 		return;
@@ -48,15 +48,29 @@
 	 * when an active trigger is comming in. This could
 	 * cause some ioapics to mal-function.
 	 * Being paranoid i guess!
+	 *
+	 * For correct operation this depends on the caller
+	 * masking the irqs.
 	 */
 	if (likely(!cpus_empty(tmp))) {
-		if (likely(!(desc->status & IRQ_DISABLED)))
-			desc->chip->disable(irq);
-
 		desc->chip->set_affinity(irq,tmp);
-
-		if (likely(!(desc->status & IRQ_DISABLED)))
-			desc->chip->enable(irq);
 	}
 	cpus_clear(irq_desc[irq].pending_mask);
 }
+
+void move_native_irq(int irq)
+{
+	struct irq_desc *desc = irq_desc + irq;
+
+	if (likely(!(desc->status & IRQ_MOVE_PENDING)))
+		return;
+
+	if (likely(!(desc->status & IRQ_DISABLED)))
+		desc->chip->disable(irq);
+
+	move_masked_irq(irq);
+
+	if (likely(!(desc->status & IRQ_DISABLED)))
+		desc->chip->enable(irq);
+}
+
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 523e464..26bb5ff 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -71,9 +71,6 @@
 static int blimit = 10;
 static int qhimark = 10000;
 static int qlowmark = 100;
-#ifdef CONFIG_SMP
-static int rsinterval = 1000;
-#endif
 
 static atomic_t rcu_barrier_cpu_count;
 static DEFINE_MUTEX(rcu_barrier_mutex);
@@ -86,8 +83,8 @@
 	int cpu;
 	cpumask_t cpumask;
 	set_need_resched();
-	if (unlikely(rdp->qlen - rdp->last_rs_qlen > rsinterval)) {
-		rdp->last_rs_qlen = rdp->qlen;
+	if (unlikely(!rcp->signaled)) {
+		rcp->signaled = 1;
 		/*
 		 * Don't send IPI to itself. With irqs disabled,
 		 * rdp->cpu is the current cpu.
@@ -301,6 +298,7 @@
 		smp_mb();
 		cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);
 
+		rcp->signaled = 0;
 	}
 }
 
@@ -628,9 +626,6 @@
 module_param(blimit, int, 0);
 module_param(qhimark, int, 0);
 module_param(qlowmark, int, 0);
-#ifdef CONFIG_SMP
-module_param(rsinterval, int, 0);
-#endif
 EXPORT_SYMBOL_GPL(rcu_batches_completed);
 EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
 EXPORT_SYMBOL_GPL(call_rcu);
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 23446e9..e2bda18 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -15,9 +15,10 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * Copyright (C) IBM Corporation, 2005
+ * Copyright (C) IBM Corporation, 2005, 2006
  *
  * Authors: Paul E. McKenney <paulmck@us.ibm.com>
+ *          Josh Triplett <josh@freedesktop.org>
  *
  * See also:  Documentation/RCU/torture.txt
  */
@@ -44,19 +45,25 @@
 #include <linux/delay.h>
 #include <linux/byteorder/swabb.h>
 #include <linux/stat.h>
+#include <linux/srcu.h>
 
 MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
+              "Josh Triplett <josh@freedesktop.org>");
 
 static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */
+static int nfakewriters = 4;	/* # fake writer threads */
 static int stat_interval;	/* Interval between stats, in seconds. */
 				/*  Defaults to "only at end of test". */
 static int verbose;		/* Print more debug info. */
 static int test_no_idle_hz;	/* Test RCU's support for tickless idle CPUs. */
 static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
-static char *torture_type = "rcu"; /* What to torture. */
+static char *torture_type = "rcu"; /* What RCU implementation to torture. */
 
 module_param(nreaders, int, 0);
 MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
+module_param(nfakewriters, int, 0);
+MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
 module_param(stat_interval, int, 0);
 MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
 module_param(verbose, bool, 0);
@@ -66,7 +73,7 @@
 module_param(shuffle_interval, int, 0);
 MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
 module_param(torture_type, charp, 0);
-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)");
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
 
 #define TORTURE_FLAG "-torture:"
 #define PRINTK_STRING(s) \
@@ -80,6 +87,7 @@
 
 static int nrealreaders;
 static struct task_struct *writer_task;
+static struct task_struct **fakewriter_tasks;
 static struct task_struct **reader_tasks;
 static struct task_struct *stats_task;
 static struct task_struct *shuffler_task;
@@ -104,11 +112,12 @@
 static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
 	{ 0 };
 static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
-atomic_t n_rcu_torture_alloc;
-atomic_t n_rcu_torture_alloc_fail;
-atomic_t n_rcu_torture_free;
-atomic_t n_rcu_torture_mberror;
-atomic_t n_rcu_torture_error;
+static atomic_t n_rcu_torture_alloc;
+static atomic_t n_rcu_torture_alloc_fail;
+static atomic_t n_rcu_torture_free;
+static atomic_t n_rcu_torture_mberror;
+static atomic_t n_rcu_torture_error;
+static struct list_head rcu_torture_removed;
 
 /*
  * Allocate an element from the rcu_tortures pool.
@@ -145,7 +154,7 @@
 
 struct rcu_random_state {
 	unsigned long rrs_state;
-	unsigned long rrs_count;
+	long rrs_count;
 };
 
 #define RCU_RANDOM_MULT 39916801  /* prime */
@@ -158,7 +167,7 @@
  * Crude but fast random-number generator.  Uses a linear congruential
  * generator, with occasional help from get_random_bytes().
  */
-static long
+static unsigned long
 rcu_random(struct rcu_random_state *rrsp)
 {
 	long refresh;
@@ -180,9 +189,11 @@
 	void (*init)(void);
 	void (*cleanup)(void);
 	int (*readlock)(void);
+	void (*readdelay)(struct rcu_random_state *rrsp);
 	void (*readunlock)(int idx);
 	int (*completed)(void);
 	void (*deferredfree)(struct rcu_torture *p);
+	void (*sync)(void);
 	int (*stats)(char *page);
 	char *name;
 };
@@ -198,6 +209,18 @@
 	return 0;
 }
 
+static void rcu_read_delay(struct rcu_random_state *rrsp)
+{
+	long delay;
+	const long longdelay = 200;
+
+	/* We want there to be long-running readers, but not all the time. */
+
+	delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay);
+	if (!delay)
+		udelay(longdelay);
+}
+
 static void rcu_torture_read_unlock(int idx) __releases(RCU)
 {
 	rcu_read_unlock();
@@ -239,13 +262,54 @@
 	.init = NULL,
 	.cleanup = NULL,
 	.readlock = rcu_torture_read_lock,
+	.readdelay = rcu_read_delay,
 	.readunlock = rcu_torture_read_unlock,
 	.completed = rcu_torture_completed,
 	.deferredfree = rcu_torture_deferred_free,
+	.sync = synchronize_rcu,
 	.stats = NULL,
 	.name = "rcu"
 };
 
+static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
+{
+	int i;
+	struct rcu_torture *rp;
+	struct rcu_torture *rp1;
+
+	cur_ops->sync();
+	list_add(&p->rtort_free, &rcu_torture_removed);
+	list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
+		i = rp->rtort_pipe_count;
+		if (i > RCU_TORTURE_PIPE_LEN)
+			i = RCU_TORTURE_PIPE_LEN;
+		atomic_inc(&rcu_torture_wcount[i]);
+		if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
+			rp->rtort_mbtest = 0;
+			list_del(&rp->rtort_free);
+			rcu_torture_free(rp);
+		}
+	}
+}
+
+static void rcu_sync_torture_init(void)
+{
+	INIT_LIST_HEAD(&rcu_torture_removed);
+}
+
+static struct rcu_torture_ops rcu_sync_ops = {
+	.init = rcu_sync_torture_init,
+	.cleanup = NULL,
+	.readlock = rcu_torture_read_lock,
+	.readdelay = rcu_read_delay,
+	.readunlock = rcu_torture_read_unlock,
+	.completed = rcu_torture_completed,
+	.deferredfree = rcu_sync_torture_deferred_free,
+	.sync = synchronize_rcu,
+	.stats = NULL,
+	.name = "rcu_sync"
+};
+
 /*
  * Definitions for rcu_bh torture testing.
  */
@@ -271,19 +335,176 @@
 	call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
 }
 
+struct rcu_bh_torture_synchronize {
+	struct rcu_head head;
+	struct completion completion;
+};
+
+static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
+{
+	struct rcu_bh_torture_synchronize *rcu;
+
+	rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
+	complete(&rcu->completion);
+}
+
+static void rcu_bh_torture_synchronize(void)
+{
+	struct rcu_bh_torture_synchronize rcu;
+
+	init_completion(&rcu.completion);
+	call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
+	wait_for_completion(&rcu.completion);
+}
+
 static struct rcu_torture_ops rcu_bh_ops = {
 	.init = NULL,
 	.cleanup = NULL,
 	.readlock = rcu_bh_torture_read_lock,
+	.readdelay = rcu_read_delay,  /* just reuse rcu's version. */
 	.readunlock = rcu_bh_torture_read_unlock,
 	.completed = rcu_bh_torture_completed,
 	.deferredfree = rcu_bh_torture_deferred_free,
+	.sync = rcu_bh_torture_synchronize,
 	.stats = NULL,
 	.name = "rcu_bh"
 };
 
+static struct rcu_torture_ops rcu_bh_sync_ops = {
+	.init = rcu_sync_torture_init,
+	.cleanup = NULL,
+	.readlock = rcu_bh_torture_read_lock,
+	.readdelay = rcu_read_delay,  /* just reuse rcu's version. */
+	.readunlock = rcu_bh_torture_read_unlock,
+	.completed = rcu_bh_torture_completed,
+	.deferredfree = rcu_sync_torture_deferred_free,
+	.sync = rcu_bh_torture_synchronize,
+	.stats = NULL,
+	.name = "rcu_bh_sync"
+};
+
+/*
+ * Definitions for srcu torture testing.
+ */
+
+static struct srcu_struct srcu_ctl;
+
+static void srcu_torture_init(void)
+{
+	init_srcu_struct(&srcu_ctl);
+	rcu_sync_torture_init();
+}
+
+static void srcu_torture_cleanup(void)
+{
+	synchronize_srcu(&srcu_ctl);
+	cleanup_srcu_struct(&srcu_ctl);
+}
+
+static int srcu_torture_read_lock(void)
+{
+	return srcu_read_lock(&srcu_ctl);
+}
+
+static void srcu_read_delay(struct rcu_random_state *rrsp)
+{
+	long delay;
+	const long uspertick = 1000000 / HZ;
+	const long longdelay = 10;
+
+	/* We want there to be long-running readers, but not all the time. */
+
+	delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
+	if (!delay)
+		schedule_timeout_interruptible(longdelay);
+}
+
+static void srcu_torture_read_unlock(int idx)
+{
+	srcu_read_unlock(&srcu_ctl, idx);
+}
+
+static int srcu_torture_completed(void)
+{
+	return srcu_batches_completed(&srcu_ctl);
+}
+
+static void srcu_torture_synchronize(void)
+{
+	synchronize_srcu(&srcu_ctl);
+}
+
+static int srcu_torture_stats(char *page)
+{
+	int cnt = 0;
+	int cpu;
+	int idx = srcu_ctl.completed & 0x1;
+
+	cnt += sprintf(&page[cnt], "%s%s per-CPU(idx=%d):",
+		       torture_type, TORTURE_FLAG, idx);
+	for_each_possible_cpu(cpu) {
+		cnt += sprintf(&page[cnt], " %d(%d,%d)", cpu,
+			       per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
+			       per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
+	}
+	cnt += sprintf(&page[cnt], "\n");
+	return cnt;
+}
+
+static struct rcu_torture_ops srcu_ops = {
+	.init = srcu_torture_init,
+	.cleanup = srcu_torture_cleanup,
+	.readlock = srcu_torture_read_lock,
+	.readdelay = srcu_read_delay,
+	.readunlock = srcu_torture_read_unlock,
+	.completed = srcu_torture_completed,
+	.deferredfree = rcu_sync_torture_deferred_free,
+	.sync = srcu_torture_synchronize,
+	.stats = srcu_torture_stats,
+	.name = "srcu"
+};
+
+/*
+ * Definitions for sched torture testing.
+ */
+
+static int sched_torture_read_lock(void)
+{
+	preempt_disable();
+	return 0;
+}
+
+static void sched_torture_read_unlock(int idx)
+{
+	preempt_enable();
+}
+
+static int sched_torture_completed(void)
+{
+	return 0;
+}
+
+static void sched_torture_synchronize(void)
+{
+	synchronize_sched();
+}
+
+static struct rcu_torture_ops sched_ops = {
+	.init = rcu_sync_torture_init,
+	.cleanup = NULL,
+	.readlock = sched_torture_read_lock,
+	.readdelay = rcu_read_delay,  /* just reuse rcu's version. */
+	.readunlock = sched_torture_read_unlock,
+	.completed = sched_torture_completed,
+	.deferredfree = rcu_sync_torture_deferred_free,
+	.sync = sched_torture_synchronize,
+	.stats = NULL,
+	.name = "sched"
+};
+
 static struct rcu_torture_ops *torture_ops[] =
-	{ &rcu_ops, &rcu_bh_ops, NULL };
+	{ &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops,
+	  &sched_ops, NULL };
 
 /*
  * RCU torture writer kthread.  Repeatedly substitutes a new structure
@@ -330,6 +551,30 @@
 }
 
 /*
+ * RCU torture fake writer kthread.  Repeatedly calls sync, with a random
+ * delay between calls.
+ */
+static int
+rcu_torture_fakewriter(void *arg)
+{
+	DEFINE_RCU_RANDOM(rand);
+
+	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
+	set_user_nice(current, 19);
+
+	do {
+		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
+		udelay(rcu_random(&rand) & 0x3ff);
+		cur_ops->sync();
+	} while (!kthread_should_stop() && !fullstop);
+
+	VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
+	while (!kthread_should_stop())
+		schedule_timeout_uninterruptible(1);
+	return 0;
+}
+
+/*
  * RCU torture reader kthread.  Repeatedly dereferences rcu_torture_current,
  * incrementing the corresponding element of the pipeline array.  The
  * counter in the element should never be greater than 1, otherwise, the
@@ -359,7 +604,7 @@
 		}
 		if (p->rtort_mbtest == 0)
 			atomic_inc(&n_rcu_torture_mberror);
-		udelay(rcu_random(&rand) & 0x7f);
+		cur_ops->readdelay(&rand);
 		preempt_disable();
 		pipe_count = p->rtort_pipe_count;
 		if (pipe_count > RCU_TORTURE_PIPE_LEN) {
@@ -483,7 +728,7 @@
 /* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
  * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
  */
-void rcu_torture_shuffle_tasks(void)
+static void rcu_torture_shuffle_tasks(void)
 {
 	cpumask_t tmp_mask = CPU_MASK_ALL;
 	int i;
@@ -507,6 +752,12 @@
 				set_cpus_allowed(reader_tasks[i], tmp_mask);
 	}
 
+	if (fakewriter_tasks != NULL) {
+		for (i = 0; i < nfakewriters; i++)
+			if (fakewriter_tasks[i])
+				set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
+	}
+
 	if (writer_task)
 		set_cpus_allowed(writer_task, tmp_mask);
 
@@ -540,11 +791,12 @@
 static inline void
 rcu_torture_print_module_parms(char *tag)
 {
-	printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
+	printk(KERN_ALERT "%s" TORTURE_FLAG
+		"--- %s: nreaders=%d nfakewriters=%d "
 		"stat_interval=%d verbose=%d test_no_idle_hz=%d "
 		"shuffle_interval = %d\n",
-		torture_type, tag, nrealreaders, stat_interval, verbose,
-		test_no_idle_hz, shuffle_interval);
+		torture_type, tag, nrealreaders, nfakewriters,
+		stat_interval, verbose, test_no_idle_hz, shuffle_interval);
 }
 
 static void
@@ -579,6 +831,19 @@
 	}
 	rcu_torture_current = NULL;
 
+	if (fakewriter_tasks != NULL) {
+		for (i = 0; i < nfakewriters; i++) {
+			if (fakewriter_tasks[i] != NULL) {
+				VERBOSE_PRINTK_STRING(
+					"Stopping rcu_torture_fakewriter task");
+				kthread_stop(fakewriter_tasks[i]);
+			}
+			fakewriter_tasks[i] = NULL;
+		}
+		kfree(fakewriter_tasks);
+		fakewriter_tasks = NULL;
+	}
+
 	if (stats_task != NULL) {
 		VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
 		kthread_stop(stats_task);
@@ -666,7 +931,25 @@
 		writer_task = NULL;
 		goto unwind;
 	}
-	reader_tasks = kmalloc(nrealreaders * sizeof(reader_tasks[0]),
+	fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
+	                           GFP_KERNEL);
+	if (fakewriter_tasks == NULL) {
+		VERBOSE_PRINTK_ERRSTRING("out of memory");
+		firsterr = -ENOMEM;
+		goto unwind;
+	}
+	for (i = 0; i < nfakewriters; i++) {
+		VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
+		fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
+		                                  "rcu_torture_fakewriter");
+		if (IS_ERR(fakewriter_tasks[i])) {
+			firsterr = PTR_ERR(fakewriter_tasks[i]);
+			VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
+			fakewriter_tasks[i] = NULL;
+			goto unwind;
+		}
+	}
+	reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
 			       GFP_KERNEL);
 	if (reader_tasks == NULL) {
 		VERBOSE_PRINTK_ERRSTRING("out of memory");
diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c
index 0c1faa9..da8d6bf 100644
--- a/kernel/rtmutex-debug.c
+++ b/kernel/rtmutex-debug.c
@@ -16,7 +16,6 @@
  *
  * See rt.c in preempt-rt for proper credits and further information
  */
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/module.h>
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
index 948bd8f..6dcea9d 100644
--- a/kernel/rtmutex-tester.c
+++ b/kernel/rtmutex-tester.c
@@ -6,7 +6,6 @@
  *  Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
  *
  */
-#include <linux/config.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/sched.h>
diff --git a/kernel/srcu.c b/kernel/srcu.c
new file mode 100644
index 0000000..3507cab
--- /dev/null
+++ b/kernel/srcu.c
@@ -0,0 +1,258 @@
+/*
+ * Sleepable Read-Copy Update mechanism for mutual exclusion.
+ *
+ * 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.
+ *
+ * Copyright (C) IBM Corporation, 2006
+ *
+ * Author: Paul McKenney <paulmck@us.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * 		Documentation/RCU/ *.txt
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/percpu.h>
+#include <linux/preempt.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/srcu.h>
+
+/**
+ * init_srcu_struct - initialize a sleep-RCU structure
+ * @sp: structure to initialize.
+ *
+ * Must invoke this on a given srcu_struct before passing that srcu_struct
+ * to any other function.  Each srcu_struct represents a separate domain
+ * of SRCU protection.
+ */
+int init_srcu_struct(struct srcu_struct *sp)
+{
+	sp->completed = 0;
+	mutex_init(&sp->mutex);
+	sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
+	return (sp->per_cpu_ref ? 0 : -ENOMEM);
+}
+
+/*
+ * srcu_readers_active_idx -- returns approximate number of readers
+ *	active on the specified rank of per-CPU counters.
+ */
+
+static int srcu_readers_active_idx(struct srcu_struct *sp, int idx)
+{
+	int cpu;
+	int sum;
+
+	sum = 0;
+	for_each_possible_cpu(cpu)
+		sum += per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx];
+	return sum;
+}
+
+/**
+ * srcu_readers_active - returns approximate number of readers.
+ * @sp: which srcu_struct to count active readers (holding srcu_read_lock).
+ *
+ * Note that this is not an atomic primitive, and can therefore suffer
+ * severe errors when invoked on an active srcu_struct.  That said, it
+ * can be useful as an error check at cleanup time.
+ */
+int srcu_readers_active(struct srcu_struct *sp)
+{
+	return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1);
+}
+
+/**
+ * cleanup_srcu_struct - deconstruct a sleep-RCU structure
+ * @sp: structure to clean up.
+ *
+ * Must invoke this after you are finished using a given srcu_struct that
+ * was initialized via init_srcu_struct(), else you leak memory.
+ */
+void cleanup_srcu_struct(struct srcu_struct *sp)
+{
+	int sum;
+
+	sum = srcu_readers_active(sp);
+	WARN_ON(sum);  /* Leakage unless caller handles error. */
+	if (sum != 0)
+		return;
+	free_percpu(sp->per_cpu_ref);
+	sp->per_cpu_ref = NULL;
+}
+
+/**
+ * srcu_read_lock - register a new reader for an SRCU-protected structure.
+ * @sp: srcu_struct in which to register the new reader.
+ *
+ * Counts the new reader in the appropriate per-CPU element of the
+ * srcu_struct.  Must be called from process context.
+ * Returns an index that must be passed to the matching srcu_read_unlock().
+ */
+int srcu_read_lock(struct srcu_struct *sp)
+{
+	int idx;
+
+	preempt_disable();
+	idx = sp->completed & 0x1;
+	barrier();  /* ensure compiler looks -once- at sp->completed. */
+	per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]++;
+	srcu_barrier();  /* ensure compiler won't misorder critical section. */
+	preempt_enable();
+	return idx;
+}
+
+/**
+ * srcu_read_unlock - unregister a old reader from an SRCU-protected structure.
+ * @sp: srcu_struct in which to unregister the old reader.
+ * @idx: return value from corresponding srcu_read_lock().
+ *
+ * Removes the count for the old reader from the appropriate per-CPU
+ * element of the srcu_struct.  Note that this may well be a different
+ * CPU than that which was incremented by the corresponding srcu_read_lock().
+ * Must be called from process context.
+ */
+void srcu_read_unlock(struct srcu_struct *sp, int idx)
+{
+	preempt_disable();
+	srcu_barrier();  /* ensure compiler won't misorder critical section. */
+	per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--;
+	preempt_enable();
+}
+
+/**
+ * synchronize_srcu - wait for prior SRCU read-side critical-section completion
+ * @sp: srcu_struct with which to synchronize.
+ *
+ * Flip the completed counter, and wait for the old count to drain to zero.
+ * As with classic RCU, the updater must use some separate means of
+ * synchronizing concurrent updates.  Can block; must be called from
+ * process context.
+ *
+ * Note that it is illegal to call synchornize_srcu() from the corresponding
+ * SRCU read-side critical section; doing so will result in deadlock.
+ * However, it is perfectly legal to call synchronize_srcu() on one
+ * srcu_struct from some other srcu_struct's read-side critical section.
+ */
+void synchronize_srcu(struct srcu_struct *sp)
+{
+	int idx;
+
+	idx = sp->completed;
+	mutex_lock(&sp->mutex);
+
+	/*
+	 * Check to see if someone else did the work for us while we were
+	 * waiting to acquire the lock.  We need -two- advances of
+	 * the counter, not just one.  If there was but one, we might have
+	 * shown up -after- our helper's first synchronize_sched(), thus
+	 * having failed to prevent CPU-reordering races with concurrent
+	 * srcu_read_unlock()s on other CPUs (see comment below).  So we
+	 * either (1) wait for two or (2) supply the second ourselves.
+	 */
+
+	if ((sp->completed - idx) >= 2) {
+		mutex_unlock(&sp->mutex);
+		return;
+	}
+
+	synchronize_sched();  /* Force memory barrier on all CPUs. */
+
+	/*
+	 * The preceding synchronize_sched() ensures that any CPU that
+	 * sees the new value of sp->completed will also see any preceding
+	 * changes to data structures made by this CPU.  This prevents
+	 * some other CPU from reordering the accesses in its SRCU
+	 * read-side critical section to precede the corresponding
+	 * srcu_read_lock() -- ensuring that such references will in
+	 * fact be protected.
+	 *
+	 * So it is now safe to do the flip.
+	 */
+
+	idx = sp->completed & 0x1;
+	sp->completed++;
+
+	synchronize_sched();  /* Force memory barrier on all CPUs. */
+
+	/*
+	 * At this point, because of the preceding synchronize_sched(),
+	 * all srcu_read_lock() calls using the old counters have completed.
+	 * Their corresponding critical sections might well be still
+	 * executing, but the srcu_read_lock() primitives themselves
+	 * will have finished executing.
+	 */
+
+	while (srcu_readers_active_idx(sp, idx))
+		schedule_timeout_interruptible(1);
+
+	synchronize_sched();  /* Force memory barrier on all CPUs. */
+
+	/*
+	 * The preceding synchronize_sched() forces all srcu_read_unlock()
+	 * primitives that were executing concurrently with the preceding
+	 * for_each_possible_cpu() loop to have completed by this point.
+	 * More importantly, it also forces the corresponding SRCU read-side
+	 * critical sections to have also completed, and the corresponding
+	 * references to SRCU-protected data items to be dropped.
+	 *
+	 * Note:
+	 *
+	 *	Despite what you might think at first glance, the
+	 *	preceding synchronize_sched() -must- be within the
+	 *	critical section ended by the following mutex_unlock().
+	 *	Otherwise, a task taking the early exit can race
+	 *	with a srcu_read_unlock(), which might have executed
+	 *	just before the preceding srcu_readers_active() check,
+	 *	and whose CPU might have reordered the srcu_read_unlock()
+	 *	with the preceding critical section.  In this case, there
+	 *	is nothing preventing the synchronize_sched() task that is
+	 *	taking the early exit from freeing a data structure that
+	 *	is still being referenced (out of order) by the task
+	 *	doing the srcu_read_unlock().
+	 *
+	 *	Alternatively, the comparison with "2" on the early exit
+	 *	could be changed to "3", but this increases synchronize_srcu()
+	 *	latency for bulk loads.  So the current code is preferred.
+	 */
+
+	mutex_unlock(&sp->mutex);
+}
+
+/**
+ * srcu_batches_completed - return batches completed.
+ * @sp: srcu_struct on which to report batch completion.
+ *
+ * Report the number of batches, correlated with, but not necessarily
+ * precisely the same as, the number of grace periods that have elapsed.
+ */
+
+long srcu_batches_completed(struct srcu_struct *sp)
+{
+	return sp->completed;
+}
+
+EXPORT_SYMBOL_GPL(init_srcu_struct);
+EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
+EXPORT_SYMBOL_GPL(srcu_read_lock);
+EXPORT_SYMBOL_GPL(srcu_read_unlock);
+EXPORT_SYMBOL_GPL(synchronize_srcu);
+EXPORT_SYMBOL_GPL(srcu_batches_completed);
+EXPORT_SYMBOL_GPL(srcu_readers_active);
diff --git a/kernel/sys.c b/kernel/sys.c
index 2314867..98489d8 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -153,7 +153,7 @@
 
 /*
  *	Atomic notifier chain routines.  Registration and unregistration
- *	use a mutex, and call_chain is synchronized by RCU (no locks).
+ *	use a spinlock, and call_chain is synchronized by RCU (no locks).
  */
 
 /**
@@ -401,6 +401,129 @@
 
 EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
 
+/*
+ *	SRCU notifier chain routines.    Registration and unregistration
+ *	use a mutex, and call_chain is synchronized by SRCU (no locks).
+ */
+
+/**
+ *	srcu_notifier_chain_register - Add notifier to an SRCU notifier chain
+ *	@nh: Pointer to head of the SRCU notifier chain
+ *	@n: New entry in notifier chain
+ *
+ *	Adds a notifier to an SRCU notifier chain.
+ *	Must be called in process context.
+ *
+ *	Currently always returns zero.
+ */
+
+int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+		struct notifier_block *n)
+{
+	int ret;
+
+	/*
+	 * This code gets used during boot-up, when task switching is
+	 * not yet working and interrupts must remain disabled.  At
+	 * such times we must not call mutex_lock().
+	 */
+	if (unlikely(system_state == SYSTEM_BOOTING))
+		return notifier_chain_register(&nh->head, n);
+
+	mutex_lock(&nh->mutex);
+	ret = notifier_chain_register(&nh->head, n);
+	mutex_unlock(&nh->mutex);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_chain_register);
+
+/**
+ *	srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain
+ *	@nh: Pointer to head of the SRCU notifier chain
+ *	@n: Entry to remove from notifier chain
+ *
+ *	Removes a notifier from an SRCU notifier chain.
+ *	Must be called from process context.
+ *
+ *	Returns zero on success or %-ENOENT on failure.
+ */
+int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+		struct notifier_block *n)
+{
+	int ret;
+
+	/*
+	 * This code gets used during boot-up, when task switching is
+	 * not yet working and interrupts must remain disabled.  At
+	 * such times we must not call mutex_lock().
+	 */
+	if (unlikely(system_state == SYSTEM_BOOTING))
+		return notifier_chain_unregister(&nh->head, n);
+
+	mutex_lock(&nh->mutex);
+	ret = notifier_chain_unregister(&nh->head, n);
+	mutex_unlock(&nh->mutex);
+	synchronize_srcu(&nh->srcu);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
+
+/**
+ *	srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ *	@nh: Pointer to head of the SRCU notifier chain
+ *	@val: Value passed unmodified to notifier function
+ *	@v: Pointer passed unmodified to notifier function
+ *
+ *	Calls each function in a notifier chain in turn.  The functions
+ *	run in a process context, so they are allowed to block.
+ *
+ *	If the return value of the notifier can be and'ed
+ *	with %NOTIFY_STOP_MASK then srcu_notifier_call_chain
+ *	will return immediately, with the return value of
+ *	the notifier function which halted execution.
+ *	Otherwise the return value is the return value
+ *	of the last notifier function called.
+ */
+
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+		unsigned long val, void *v)
+{
+	int ret;
+	int idx;
+
+	idx = srcu_read_lock(&nh->srcu);
+	ret = notifier_call_chain(&nh->head, val, v);
+	srcu_read_unlock(&nh->srcu, idx);
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
+
+/**
+ *	srcu_init_notifier_head - Initialize an SRCU notifier head
+ *	@nh: Pointer to head of the srcu notifier chain
+ *
+ *	Unlike other sorts of notifier heads, SRCU notifier heads require
+ *	dynamic initialization.  Be sure to call this routine before
+ *	calling any of the other SRCU notifier routines for this head.
+ *
+ *	If an SRCU notifier head is deallocated, it must first be cleaned
+ *	up by calling srcu_cleanup_notifier_head().  Otherwise the head's
+ *	per-cpu data (used by the SRCU mechanism) will leak.
+ */
+
+void srcu_init_notifier_head(struct srcu_notifier_head *nh)
+{
+	mutex_init(&nh->mutex);
+	if (init_srcu_struct(&nh->srcu) < 0)
+		BUG();
+	nh->head = NULL;
+}
+
+EXPORT_SYMBOL_GPL(srcu_init_notifier_head);
+
 /**
  *	register_reboot_notifier - Register function to be called at reboot time
  *	@nb: Info about notifier function to be called
diff --git a/mm/filemap.c b/mm/filemap.c
index ec4692359..3464b68 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1139,11 +1139,11 @@
 }
 
 /**
- * __generic_file_aio_read - generic filesystem read routine
+ * generic_file_aio_read - generic filesystem read routine
  * @iocb:	kernel I/O control block
  * @iov:	io vector request
  * @nr_segs:	number of segments in the iovec
- * @ppos:	current file position
+ * @pos:	current file position
  *
  * This is the "read()" routine for all filesystems
  * that can use the page cache directly.
@@ -1198,8 +1198,10 @@
 			if (retval > 0)
 				*ppos = pos + retval;
 		}
-		file_accessed(filp);
-		goto out;
+		if (likely(retval != 0)) {
+			file_accessed(filp);
+			goto out;
+		}
 	}
 
 	retval = 0;
diff --git a/mm/filemap.h b/mm/filemap.h
index 3f2a343..c2bff04 100644
--- a/mm/filemap.h
+++ b/mm/filemap.h
@@ -12,7 +12,6 @@
 #include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/uio.h>
-#include <linux/config.h>
 #include <linux/uaccess.h>
 
 size_t
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7c7d03d..1d709ff 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -364,6 +364,8 @@
 	pte_t *ptep;
 	pte_t pte;
 	struct page *page;
+	struct page *tmp;
+	LIST_HEAD(page_list);
 
 	WARN_ON(!is_vm_hugetlb_page(vma));
 	BUG_ON(start & ~HPAGE_MASK);
@@ -384,12 +386,16 @@
 			continue;
 
 		page = pte_page(pte);
-		put_page(page);
+		list_add(&page->lru, &page_list);
 		add_mm_counter(mm, file_rss, (int) -(HPAGE_SIZE / PAGE_SIZE));
 	}
 
 	spin_unlock(&mm->page_table_lock);
 	flush_tlb_range(vma, start, end);
+	list_for_each_entry_safe(page, tmp, &page_list, lru) {
+		list_del(&page->lru);
+		put_page(page);
+	}
 }
 
 static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 4f59d90..a8c003e 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -900,7 +900,8 @@
 		      int classzone_idx, int alloc_flags)
 {
 	/* free_pages my go negative - that's OK */
-	long min = mark, free_pages = z->free_pages - (1 << order) + 1;
+	unsigned long min = mark;
+	long free_pages = z->free_pages - (1 << order) + 1;
 	int o;
 
 	if (alloc_flags & ALLOC_HIGH)
@@ -2050,8 +2051,8 @@
 
 /**
  * free_bootmem_with_active_regions - Call free_bootmem_node for each active range
- * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed
- * @max_low_pfn: The highest PFN that till be passed to free_bootmem_node
+ * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed.
+ * @max_low_pfn: The highest PFN that will be passed to free_bootmem_node
  *
  * If an architecture guarantees that all ranges registered with
  * add_active_ranges() contain no holes and may be freed, this
@@ -2081,11 +2082,11 @@
 
 /**
  * sparse_memory_present_with_active_regions - Call memory_present for each active range
- * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used
+ * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used.
  *
  * If an architecture guarantees that all ranges registered with
  * add_active_ranges() contain no holes and may be freed, this
- * this function may be used instead of calling memory_present() manually.
+ * function may be used instead of calling memory_present() manually.
  */
 void __init sparse_memory_present_with_active_regions(int nid)
 {
@@ -2155,14 +2156,14 @@
 
 /**
  * get_pfn_range_for_nid - Return the start and end page frames for a node
- * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned
- * @start_pfn: Passed by reference. On return, it will have the node start_pfn
- * @end_pfn: Passed by reference. On return, it will have the node end_pfn
+ * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned.
+ * @start_pfn: Passed by reference. On return, it will have the node start_pfn.
+ * @end_pfn: Passed by reference. On return, it will have the node end_pfn.
  *
  * It returns the start and end page frame of a node based on information
  * provided by an arch calling add_active_range(). If called for a node
  * with no available memory, a warning is printed and the start and end
- * PFNs will be 0
+ * PFNs will be 0.
  */
 void __init get_pfn_range_for_nid(unsigned int nid,
 			unsigned long *start_pfn, unsigned long *end_pfn)
@@ -2215,7 +2216,7 @@
 
 /*
  * Return the number of holes in a range on a node. If nid is MAX_NUMNODES,
- * then all holes in the requested range will be accounted for
+ * then all holes in the requested range will be accounted for.
  */
 unsigned long __init __absent_pages_in_range(int nid,
 				unsigned long range_start_pfn,
@@ -2268,7 +2269,7 @@
  * @start_pfn: The start PFN to start searching for holes
  * @end_pfn: The end PFN to stop searching for holes
  *
- * It returns the number of pages frames in memory holes within a range
+ * It returns the number of pages frames in memory holes within a range.
  */
 unsigned long __init absent_pages_in_range(unsigned long start_pfn,
 							unsigned long end_pfn)
@@ -2582,11 +2583,12 @@
 
 /**
  * remove_all_active_ranges - Remove all currently registered regions
+ *
  * During discovery, it may be found that a table like SRAT is invalid
  * and an alternative discovery method must be used. This function removes
  * all currently registered regions.
  */
-void __init remove_all_active_ranges()
+void __init remove_all_active_ranges(void)
 {
 	memset(early_node_map, 0, sizeof(early_node_map));
 	nr_nodemap_entries = 0;
@@ -2636,7 +2638,7 @@
  * find_min_pfn_with_active_regions - Find the minimum PFN registered
  *
  * It returns the minimum PFN based on information provided via
- * add_active_range()
+ * add_active_range().
  */
 unsigned long __init find_min_pfn_with_active_regions(void)
 {
@@ -2647,7 +2649,7 @@
  * find_max_pfn_with_active_regions - Find the maximum PFN registered
  *
  * It returns the maximum PFN based on information provided via
- * add_active_range()
+ * add_active_range().
  */
 unsigned long __init find_max_pfn_with_active_regions(void)
 {
@@ -2662,10 +2664,7 @@
 
 /**
  * free_area_init_nodes - Initialise all pg_data_t and zone data
- * @arch_max_dma_pfn: The maximum PFN usable for ZONE_DMA
- * @arch_max_dma32_pfn: The maximum PFN usable for ZONE_DMA32
- * @arch_max_low_pfn: The maximum PFN usable for ZONE_NORMAL
- * @arch_max_high_pfn: The maximum PFN usable for ZONE_HIGHMEM
+ * @max_zone_pfn: an array of max PFNs for each zone
  *
  * This will call free_area_init_node() for each active node in the system.
  * Using the page ranges provided by add_active_range(), the size of each
@@ -2723,14 +2722,15 @@
 #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
 
 /**
- * set_dma_reserve - Account the specified number of pages reserved in ZONE_DMA
- * @new_dma_reserve - The number of pages to mark reserved
+ * set_dma_reserve - set the specified number of pages reserved in the first zone
+ * @new_dma_reserve: The number of pages to mark reserved
  *
  * The per-cpu batchsize and zone watermarks are determined by present_pages.
  * In the DMA zone, a significant percentage may be consumed by kernel image
  * and other unfreeable allocations which can skew the watermarks badly. This
- * function may optionally be used to account for unfreeable pages in
- * ZONE_DMA. The effect will be lower watermarks and smaller per-cpu batchsize
+ * function may optionally be used to account for unfreeable pages in the
+ * first zone (e.g., ZONE_DMA). The effect will be lower watermarks and
+ * smaller per-cpu batchsize.
  */
 void __init set_dma_reserve(unsigned long new_dma_reserve)
 {
@@ -2843,10 +2843,11 @@
 	calculate_totalreserve_pages();
 }
 
-/*
- * setup_per_zone_pages_min - called when min_free_kbytes changes.  Ensures 
- *	that the pages_{min,low,high} values for each zone are set correctly 
- *	with respect to min_free_kbytes.
+/**
+ * setup_per_zone_pages_min - called when min_free_kbytes changes.
+ *
+ * Ensures that the pages_{min,low,high} values for each zone are set correctly
+ * with respect to min_free_kbytes.
  */
 void setup_per_zone_pages_min(void)
 {
diff --git a/mm/readahead.c b/mm/readahead.c
index aa7ec42..1ba736a 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -38,6 +38,7 @@
 	ra->ra_pages = mapping->backing_dev_info->ra_pages;
 	ra->prev_page = -1;
 }
+EXPORT_SYMBOL_GPL(file_ra_state_init);
 
 /*
  * Return max readahead size for this inode in number-of-pages.
diff --git a/mm/slab.c b/mm/slab.c
index 3dbd6f4..e9a63b5 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -86,7 +86,6 @@
  *	All object allocations for a node occur from node specific slab lists.
  */
 
-#include	<linux/config.h>
 #include	<linux/slab.h>
 #include	<linux/mm.h>
 #include	<linux/poison.h>
@@ -3488,22 +3487,25 @@
 }
 
 
+#ifdef CONFIG_DEBUG_SLAB
 void *__kmalloc(size_t size, gfp_t flags)
 {
-#ifndef CONFIG_DEBUG_SLAB
-	return __do_kmalloc(size, flags, NULL);
-#else
 	return __do_kmalloc(size, flags, __builtin_return_address(0));
-#endif
 }
 EXPORT_SYMBOL(__kmalloc);
 
-#ifdef CONFIG_DEBUG_SLAB
 void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller)
 {
 	return __do_kmalloc(size, flags, caller);
 }
 EXPORT_SYMBOL(__kmalloc_track_caller);
+
+#else
+void *__kmalloc(size_t size, gfp_t flags)
+{
+	return __do_kmalloc(size, flags, NULL);
+}
+EXPORT_SYMBOL(__kmalloc);
 #endif
 
 /**
diff --git a/mm/util.c b/mm/util.c
index e14fa84..ace2aea 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -11,7 +11,7 @@
  */
 void *__kzalloc(size_t size, gfp_t flags)
 {
-	void *ret = ____kmalloc(size, flags);
+	void *ret = kmalloc_track_caller(size, flags);
 	if (ret)
 		memset(ret, 0, size);
 	return ret;
@@ -33,7 +33,7 @@
 		return NULL;
 
 	len = strlen(s) + 1;
-	buf = ____kmalloc(len, gfp);
+	buf = kmalloc_track_caller(len, gfp);
 	if (buf)
 		memcpy(buf, s, len);
 	return buf;
@@ -51,7 +51,7 @@
 {
 	void *p;
 
-	p = ____kmalloc(len, gfp);
+	p = kmalloc_track_caller(len, gfp);
 	if (p)
 		memcpy(p, src, len);
 	return p;
diff --git a/mm/vmstat.c b/mm/vmstat.c
index a2b6a9f..45b124e 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -9,7 +9,6 @@
  *		Christoph Lameter <christoph@lameter.com>
  */
 
-#include <linux/config.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/cpu.h>
diff --git a/net/atm/lec.h b/net/atm/lec.h
index 8ac6b73..877f509 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -7,7 +7,6 @@
 #ifndef _LEC_H_
 #define _LEC_H_
 
-#include <linux/config.h>
 #include <linux/atmdev.h>
 #include <linux/netdevice.h>
 #include <linux/atmlec.h>
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index 770c0df..b54306a 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -22,24 +22,37 @@
    const void *data, unsigned int datalen)
 {
 	struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+	int action = info->target & -16;
 
-	if ((*pskb)->nfmark != info->mark)
+	if (action == MARK_SET_VALUE)
 		(*pskb)->nfmark = info->mark;
+	else if (action == MARK_OR_VALUE)
+		(*pskb)->nfmark |= info->mark;
+	else if (action == MARK_AND_VALUE)
+		(*pskb)->nfmark &= info->mark;
+	else
+		(*pskb)->nfmark ^= info->mark;
 
-	return info->target;
+	return info->target | -16;
 }
 
 static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
    const struct ebt_entry *e, void *data, unsigned int datalen)
 {
 	struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+	int tmp;
 
 	if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
 		return -EINVAL;
-	if (BASE_CHAIN && info->target == EBT_RETURN)
+	tmp = info->target | -16;
+	if (BASE_CHAIN && tmp == EBT_RETURN)
 		return -EINVAL;
 	CLEAR_BASE_CHAIN_BIT;
-	if (INVALID_TARGET)
+	if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
+		return -EINVAL;
+	tmp = info->target & -16;
+	if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
+	    tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
 		return -EINVAL;
 	return 0;
 }
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index a99d87d..6b0e63c 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -8,7 +8,6 @@
  * Authors:	Thomas Graf <tgraf@suug.ch>
  */
 
-#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 8ce8c47..b4b4783 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -344,12 +344,12 @@
 {
 	struct neighbour *n;
 	int key_len = tbl->key_len;
-	u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
+	u32 hash_val = tbl->hash(pkey, dev);
 	
 	NEIGH_CACHE_STAT_INC(tbl, lookups);
 
 	read_lock_bh(&tbl->lock);
-	for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
+	for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
 		if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
 			neigh_hold(n);
 			NEIGH_CACHE_STAT_INC(tbl, hits);
@@ -364,12 +364,12 @@
 {
 	struct neighbour *n;
 	int key_len = tbl->key_len;
-	u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask;
+	u32 hash_val = tbl->hash(pkey, NULL);
 
 	NEIGH_CACHE_STAT_INC(tbl, lookups);
 
 	read_lock_bh(&tbl->lock);
-	for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
+	for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
 		if (!memcmp(n->primary_key, pkey, key_len)) {
 			neigh_hold(n);
 			NEIGH_CACHE_STAT_INC(tbl, hits);
@@ -1998,12 +1998,12 @@
 	int rc, h, s_h = cb->args[1];
 	int idx, s_idx = idx = cb->args[2];
 
+	read_lock_bh(&tbl->lock);
 	for (h = 0; h <= tbl->hash_mask; h++) {
 		if (h < s_h)
 			continue;
 		if (h > s_h)
 			s_idx = 0;
-		read_lock_bh(&tbl->lock);
 		for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) {
 			if (idx < s_idx)
 				continue;
@@ -2016,8 +2016,8 @@
 				goto out;
 			}
 		}
-		read_unlock_bh(&tbl->lock);
 	}
+	read_unlock_bh(&tbl->lock);
 	rc = skb->len;
 out:
 	cb->args[1] = h;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c448c7f..3c23760 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -156,7 +156,8 @@
 
 	/* Get the DATA. Size must match skb_add_mtu(). */
 	size = SKB_DATA_ALIGN(size);
-	data = ____kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+	data = kmalloc_track_caller(size + sizeof(struct skb_shared_info),
+			gfp_mask);
 	if (!data)
 		goto nodata;
 
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index d172a98..5572071 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -434,6 +434,15 @@
 
 	  If unsure, say Y.
 
+config INET_XFRM_MODE_BEET
+	tristate "IP: IPsec BEET mode"
+	default y
+	select XFRM
+	---help---
+	  Support for IPsec BEET mode.
+
+	  If unsure, say Y.
+
 config INET_DIAG
 	tristate "INET: socket monitoring interface"
 	default y
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index f66049e..15645c5 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -23,6 +23,7 @@
 obj-$(CONFIG_INET_ESP) += esp4.o
 obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
 obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
+obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
 obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
 obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
 obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 13b2936..b5c205b 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -253,7 +253,8 @@
 		 *    as per draft-ietf-ipsec-udp-encaps-06,
 		 *    section 3.1.2
 		 */
-		if (x->props.mode == XFRM_MODE_TRANSPORT)
+		if (x->props.mode == XFRM_MODE_TRANSPORT ||
+		    x->props.mode == XFRM_MODE_BEET)
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 
@@ -271,17 +272,28 @@
 {
 	struct esp_data *esp = x->data;
 	u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
+	int enclen = 0;
 
-	if (x->props.mode == XFRM_MODE_TUNNEL) {
-		mtu = ALIGN(mtu + 2, blksize);
-	} else {
-		/* The worst case. */
+	switch (x->props.mode) {
+	case XFRM_MODE_TUNNEL:
+		mtu = ALIGN(mtu +2, blksize);
+		break;
+	default:
+	case XFRM_MODE_TRANSPORT:
+		/* The worst case */
 		mtu = ALIGN(mtu + 2, 4) + blksize - 4;
+		break;
+	case XFRM_MODE_BEET:
+ 		/* The worst case. */
+		enclen = IPV4_BEET_PHMAXLEN;
+		mtu = ALIGN(mtu + enclen + 2, blksize);
+		break;
 	}
+
 	if (esp->conf.padlen)
 		mtu = ALIGN(mtu, esp->conf.padlen);
 
-	return mtu + x->props.header_len + esp->auth.icv_trunc_len;
+	return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;
 }
 
 static void esp4_err(struct sk_buff *skb, u32 info)
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 2017d36..3839b70 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -206,6 +206,7 @@
 static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
 {
 	struct xfrm_state *t;
+	u8 mode = XFRM_MODE_TUNNEL;
 	
 	t = xfrm_state_alloc();
 	if (t == NULL)
@@ -216,7 +217,9 @@
 	t->id.daddr.a4 = x->id.daddr.a4;
 	memcpy(&t->sel, &x->sel, sizeof(t->sel));
 	t->props.family = AF_INET;
-	t->props.mode = XFRM_MODE_TUNNEL;
+	if (x->props.mode == XFRM_MODE_BEET)
+		mode = x->props.mode;
+	t->props.mode = mode;
 	t->props.saddr.a4 = x->props.saddr.a4;
 	t->props.flags = x->props.flags;
 
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 6dee039..1445bb4 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -813,6 +813,16 @@
 	skb->nh.iph->saddr = cp->vaddr;
 	ip_send_check(skb->nh.iph);
 
+ 	/* For policy routing, packets originating from this
+ 	 * machine itself may be routed differently to packets
+ 	 * passing through.  We want this packet to be routed as
+ 	 * if it came from this machine itself.  So re-compute
+ 	 * the routing information.
+ 	 */
+ 	if (ip_route_me_harder(pskb, RTN_LOCAL) != 0)
+ 		goto drop;
+	skb = *pskb;
+
 	IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
 
 	ip_vs_out_stats(cp, skb);
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index 5ac1537..e2005c6 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -8,7 +8,7 @@
 #include <net/ip.h>
 
 /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
-int ip_route_me_harder(struct sk_buff **pskb)
+int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
 {
 	struct iphdr *iph = (*pskb)->nh.iph;
 	struct rtable *rt;
@@ -16,10 +16,13 @@
 	struct dst_entry *odst;
 	unsigned int hh_len;
 
+	if (addr_type == RTN_UNSPEC)
+		addr_type = inet_addr_type(iph->saddr);
+
 	/* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
 	 * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
 	 */
-	if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
+	if (addr_type == RTN_LOCAL) {
 		fl.nl_u.ip4_u.daddr = iph->daddr;
 		fl.nl_u.ip4_u.saddr = iph->saddr;
 		fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
@@ -156,7 +159,7 @@
 		if (!(iph->tos == rt_info->tos
 		      && iph->daddr == rt_info->daddr
 		      && iph->saddr == rt_info->saddr))
-			return ip_route_me_harder(pskb);
+			return ip_route_me_harder(pskb, RTN_UNSPEC);
 	}
 	return 0;
 }
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 021395b..d85d2de 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -265,7 +265,8 @@
 		       ct->tuplehash[!dir].tuple.src.u.all
 #endif
 		    )
-			return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+			if (ip_route_me_harder(pskb, RTN_UNSPEC))
+				ret = NF_DROP;
 	}
 	return ret;
 }
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index fd0c05e..ad0312d 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -38,76 +38,16 @@
 #define DEBUGP(format, args...)
 #endif
 
-static inline struct rtable *route_reverse(struct sk_buff *skb, 
-					   struct tcphdr *tcph, int hook)
-{
-	struct iphdr *iph = skb->nh.iph;
-	struct dst_entry *odst;
-	struct flowi fl = {};
-	struct rtable *rt;
-
-	/* 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;
-		fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
-
-		if (ip_route_output_key(&rt, &fl) != 0)
-			return NULL;
-	} else {
-		/* non-local src, find valid iif to satisfy
-		 * rp-filter when calling ip_route_input. */
-		fl.nl_u.ip4_u.daddr = iph->daddr;
-		if (ip_route_output_key(&rt, &fl) != 0)
-			return NULL;
-
-		odst = skb->dst;
-		if (ip_route_input(skb, iph->saddr, iph->daddr,
-		                   RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
-			dst_release(&rt->u.dst);
-			return NULL;
-		}
-		dst_release(&rt->u.dst);
-		rt = (struct rtable *)skb->dst;
-		skb->dst = odst;
-
-		fl.nl_u.ip4_u.daddr = iph->saddr;
-		fl.nl_u.ip4_u.saddr = iph->daddr;
-		fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
-	}
-
-	if (rt->u.dst.error) {
-		dst_release(&rt->u.dst);
-		return NULL;
-	}
-
-	fl.proto = IPPROTO_TCP;
-	fl.fl_ip_sport = tcph->dest;
-	fl.fl_ip_dport = tcph->source;
-	security_skb_classify_flow(skb, &fl);
-
-	xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
-
-	return rt;
-}
-
 /* Send RST reply */
 static void send_reset(struct sk_buff *oldskb, int hook)
 {
 	struct sk_buff *nskb;
 	struct iphdr *iph = oldskb->nh.iph;
 	struct tcphdr _otcph, *oth, *tcph;
-	struct rtable *rt;
 	__be16 tmp_port;
 	__be32 tmp_addr;
 	int needs_ack;
-	int hh_len;
+	unsigned int addr_type;
 
 	/* IP header checks: fragment. */
 	if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
@@ -126,23 +66,13 @@
 	if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
 		return;
 
-	if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
-		return;
-
-	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
-
 	/* We need a linear, writeable skb.  We also need to expand
 	   headroom in case hh_len of incoming interface < hh_len of
 	   outgoing interface */
-	nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
+	nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
 			       GFP_ATOMIC);
-	if (!nskb) {
-		dst_release(&rt->u.dst);
+	if (!nskb)
 		return;
-	}
-
-	dst_release(nskb->dst);
-	nskb->dst = &rt->u.dst;
 
 	/* This packet will not be the same as the other: clear nf fields */
 	nf_reset(nskb);
@@ -184,6 +114,21 @@
 	tcph->window = 0;
 	tcph->urg_ptr = 0;
 
+	/* Set DF, id = 0 */
+	nskb->nh.iph->frag_off = htons(IP_DF);
+	nskb->nh.iph->id = 0;
+
+	addr_type = RTN_UNSPEC;
+	if (hook != NF_IP_FORWARD
+#ifdef CONFIG_BRIDGE_NETFILTER
+	    || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
+#endif
+	   )
+		addr_type = RTN_LOCAL;
+
+	if (ip_route_me_harder(&nskb, addr_type))
+		goto free_nskb;
+
 	/* Adjust TCP checksum */
 	nskb->ip_summed = CHECKSUM_NONE;
 	tcph->check = 0;
@@ -192,12 +137,8 @@
 				   nskb->nh.iph->daddr,
 				   csum_partial((char *)tcph,
 						sizeof(struct tcphdr), 0));
-
-	/* Adjust IP TTL, DF */
+	/* Adjust IP TTL */
 	nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
-	/* Set DF, id = 0 */
-	nskb->nh.iph->frag_off = htons(IP_DF);
-	nskb->nh.iph->id = 0;
 
 	/* Adjust IP checksum */
 	nskb->nh.iph->check = 0;
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index e62ea2b..b91f358 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -157,7 +157,8 @@
 		|| (*pskb)->nfmark != nfmark
 #endif
 		|| (*pskb)->nh.iph->tos != tos))
-		return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+		if (ip_route_me_harder(pskb, RTN_UNSPEC))
+			ret = NF_DROP;
 
 	return ret;
 }
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3f884ce..cf06acc 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2259,7 +2259,7 @@
 	u32 pkts_acked = 0;
 	void (*rtt_sample)(struct sock *sk, u32 usrtt)
 		= icsk->icsk_ca_ops->rtt_sample;
-	struct timeval tv;
+	struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
 
 	while ((skb = skb_peek(&sk->sk_write_queue)) &&
 	       skb != sk->sk_send_head) {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 6d6142f..865d752 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -675,6 +675,8 @@
 		udp_flush_pending_frames(sk);
 	else if (!corkreq)
 		err = udp_push_pending_frames(sk, up);
+	else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
+		up->pending = 0;
 	release_sock(sk);
 
 out:
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
new file mode 100644
index 0000000..89cf59e
--- /dev/null
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -0,0 +1,139 @@
+/*
+ * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4.
+ *
+ * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com>
+ *                    Miika Komu     <miika@iki.fi>
+ *                    Herbert Xu     <herbert@gondor.apana.org.au>
+ *                    Abhinav Pathak <abhinav.pathak@hiit.fi>
+ *                    Jeff Ahrenholz <ahrenholz@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stringify.h>
+#include <net/dst.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+
+/* Add encapsulation header.
+ *
+ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
+ * The following fields in it shall be filled in by x->type->output:
+ *      tot_len
+ *      check
+ *
+ * On exit, skb->h will be set to the start of the payload to be processed
+ * by x->type->output and skb->nh will be set to the top IP header.
+ */
+static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct iphdr *iph, *top_iph = NULL;
+	int hdrlen, optlen;
+
+	iph = skb->nh.iph;
+	skb->h.ipiph = iph;
+
+	hdrlen = 0;
+	optlen = iph->ihl * 4 - sizeof(*iph);
+	if (unlikely(optlen))
+		hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
+
+	skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen);
+	top_iph = skb->nh.iph;
+	hdrlen = iph->ihl * 4 - optlen;
+	skb->h.raw += hdrlen;
+
+	memmove(top_iph, iph, hdrlen);
+	if (unlikely(optlen)) {
+		struct ip_beet_phdr *ph;
+
+		BUG_ON(optlen < 0);
+
+		ph = (struct ip_beet_phdr *)skb->h.raw;
+		ph->padlen = 4 - (optlen & 4);
+		ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8;
+		ph->nexthdr = top_iph->protocol;
+
+		top_iph->protocol = IPPROTO_BEETPH;
+		top_iph->ihl = sizeof(struct iphdr) / 4;
+	}
+
+	top_iph->saddr = x->props.saddr.a4;
+	top_iph->daddr = x->id.daddr.a4;
+
+	return 0;
+}
+
+static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct iphdr *iph = skb->nh.iph;
+	int phlen = 0;
+	int optlen = 0;
+	__u8 ph_nexthdr = 0, protocol = 0;
+	int err = -EINVAL;
+
+	protocol = iph->protocol;
+
+	if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
+		struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1);
+
+		if (!pskb_may_pull(skb, sizeof(*ph)))
+			goto out;
+
+		phlen = ph->hdrlen * 8;
+		optlen = phlen - ph->padlen - sizeof(*ph);
+		if (optlen < 0 || optlen & 3 || optlen > 250)
+			goto out;
+
+		if (!pskb_may_pull(skb, phlen))
+			goto out;
+
+		ph_nexthdr = ph->nexthdr;
+	}
+
+	skb_push(skb, sizeof(*iph) - phlen + optlen);
+	memmove(skb->data, skb->nh.raw, sizeof(*iph));
+	skb->nh.raw = skb->data;
+
+	iph = skb->nh.iph;
+	iph->ihl = (sizeof(*iph) + optlen) / 4;
+	iph->tot_len = htons(skb->len);
+	iph->daddr = x->sel.daddr.a4;
+	iph->saddr = x->sel.saddr.a4;
+	if (ph_nexthdr)
+		iph->protocol = ph_nexthdr;
+	else
+		iph->protocol = protocol;
+	iph->check = 0;
+	iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
+	err = 0;
+out:
+	return err;
+}
+
+static struct xfrm_mode xfrm4_beet_mode = {
+	.input = xfrm4_beet_input,
+	.output = xfrm4_beet_output,
+	.owner = THIS_MODULE,
+	.encap = XFRM_MODE_BEET,
+};
+
+static int __init xfrm4_beet_init(void)
+{
+	return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
+}
+
+static void __exit xfrm4_beet_exit(void)
+{
+	int err;
+
+	err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
+	BUG_ON(err);
+}
+
+module_init(xfrm4_beet_init);
+module_exit(xfrm4_beet_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index a2d211d..a460e81 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -136,6 +136,16 @@
 
 	  If unsure, say Y.
 
+config INET6_XFRM_MODE_BEET
+	tristate "IPv6: IPsec BEET mode"
+	depends on IPV6
+	default IPV6
+	select XFRM
+	---help---
+	  Support for IPsec BEET mode.
+
+	  If unsure, say Y.
+
 config INET6_XFRM_MODE_ROUTEOPTIMIZATION
 	tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)"
 	depends on IPV6 && EXPERIMENTAL
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 0213c66..87274e4 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -26,6 +26,7 @@
 obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
 obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
 obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o
+obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 34f5bfa..d8c1057 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -13,7 +13,6 @@
  *	Ville Nuorvala		<vnuorval@tcs.hut.fi>
  */
 
-#include <linux/config.h>
 #include <linux/netdevice.h>
 
 #include <net/fib_rules.h>
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index a2860e3..71f59f1 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -199,6 +199,7 @@
 static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
 {
 	struct xfrm_state *t = NULL;
+	u8 mode = XFRM_MODE_TUNNEL;
 
 	t = xfrm_state_alloc();
 	if (!t)
@@ -212,7 +213,9 @@
 	memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
 	memcpy(&t->sel, &x->sel, sizeof(t->sel));
 	t->props.family = AF_INET6;
-	t->props.mode = XFRM_MODE_TUNNEL;
+	if (x->props.mode == XFRM_MODE_BEET)
+		mode = x->props.mode;
+	t->props.mode = mode;
 	memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
 
 	if (xfrm_init_state(t))
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 99d116c..7ccdc8f 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -22,7 +22,6 @@
  *	Masahide NAKAMURA @USAGI
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/time.h>
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 9662561..e0c3934 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -546,7 +546,7 @@
 	struct in6_addr *daddr, *final_p = NULL, final;
 	struct ipv6_txoptions *opt = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
-	struct flowi *fl = &inet->cork.fl;
+	struct flowi fl;
 	struct dst_entry *dst;
 	int addr_len = msg->msg_namelen;
 	int ulen = len;
@@ -626,19 +626,19 @@
 	}
 	ulen += sizeof(struct udphdr);
 
-	memset(fl, 0, sizeof(*fl));
+	memset(&fl, 0, sizeof(fl));
 
 	if (sin6) {
 		if (sin6->sin6_port == 0)
 			return -EINVAL;
 
-		fl->fl_ip_dport = sin6->sin6_port;
+		fl.fl_ip_dport = sin6->sin6_port;
 		daddr = &sin6->sin6_addr;
 
 		if (np->sndflow) {
-			fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
-			if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
-				flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
+			fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+			if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+				flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
 				if (flowlabel == NULL)
 					return -EINVAL;
 				daddr = &flowlabel->dst;
@@ -656,32 +656,32 @@
 		if (addr_len >= sizeof(struct sockaddr_in6) &&
 		    sin6->sin6_scope_id &&
 		    ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
-			fl->oif = sin6->sin6_scope_id;
+			fl.oif = sin6->sin6_scope_id;
 	} else {
 		if (sk->sk_state != TCP_ESTABLISHED)
 			return -EDESTADDRREQ;
 
-		fl->fl_ip_dport = inet->dport;
+		fl.fl_ip_dport = inet->dport;
 		daddr = &np->daddr;
-		fl->fl6_flowlabel = np->flow_label;
+		fl.fl6_flowlabel = np->flow_label;
 		connected = 1;
 	}
 
-	if (!fl->oif)
-		fl->oif = sk->sk_bound_dev_if;
+	if (!fl.oif)
+		fl.oif = sk->sk_bound_dev_if;
 
 	if (msg->msg_controllen) {
 		opt = &opt_space;
 		memset(opt, 0, sizeof(struct ipv6_txoptions));
 		opt->tot_len = sizeof(*opt);
 
-		err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass);
+		err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
 		if (err < 0) {
 			fl6_sock_release(flowlabel);
 			return err;
 		}
-		if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
-			flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
+		if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
+			flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
 			if (flowlabel == NULL)
 				return -EINVAL;
 		}
@@ -695,39 +695,39 @@
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 	opt = ipv6_fixup_options(&opt_space, opt);
 
-	fl->proto = IPPROTO_UDP;
-	ipv6_addr_copy(&fl->fl6_dst, daddr);
-	if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr))
-		ipv6_addr_copy(&fl->fl6_src, &np->saddr);
-	fl->fl_ip_sport = inet->sport;
+	fl.proto = IPPROTO_UDP;
+	ipv6_addr_copy(&fl.fl6_dst, daddr);
+	if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
+		ipv6_addr_copy(&fl.fl6_src, &np->saddr);
+	fl.fl_ip_sport = inet->sport;
 	
 	/* merge ip6_build_xmit from ip6_output */
 	if (opt && opt->srcrt) {
 		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
-		ipv6_addr_copy(&final, &fl->fl6_dst);
-		ipv6_addr_copy(&fl->fl6_dst, rt0->addr);
+		ipv6_addr_copy(&final, &fl.fl6_dst);
+		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
 		final_p = &final;
 		connected = 0;
 	}
 
-	if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) {
-		fl->oif = np->mcast_oif;
+	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
+		fl.oif = np->mcast_oif;
 		connected = 0;
 	}
 
-	security_sk_classify_flow(sk, fl);
+	security_sk_classify_flow(sk, &fl);
 
-	err = ip6_sk_dst_lookup(sk, &dst, fl);
+	err = ip6_sk_dst_lookup(sk, &dst, &fl);
 	if (err)
 		goto out;
 	if (final_p)
-		ipv6_addr_copy(&fl->fl6_dst, final_p);
+		ipv6_addr_copy(&fl.fl6_dst, final_p);
 
-	if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0)
+	if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
 		goto out;
 
 	if (hlimit < 0) {
-		if (ipv6_addr_is_multicast(&fl->fl6_dst))
+		if (ipv6_addr_is_multicast(&fl.fl6_dst))
 			hlimit = np->mcast_hops;
 		else
 			hlimit = np->hop_limit;
@@ -763,21 +763,23 @@
 do_append_data:
 	up->len += ulen;
 	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
-		sizeof(struct udphdr), hlimit, tclass, opt, fl,
+		sizeof(struct udphdr), hlimit, tclass, opt, &fl,
 		(struct rt6_info*)dst,
 		corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
 	if (err)
 		udp_v6_flush_pending_frames(sk);
 	else if (!corkreq)
 		err = udp_v6_push_pending_frames(sk, up);
+	else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
+		up->pending = 0;
 
 	if (dst) {
 		if (connected) {
 			ip6_dst_store(sk, dst,
-				      ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ?
+				      ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
 				      &np->daddr : NULL,
 #ifdef CONFIG_IPV6_SUBTREES
-				      ipv6_addr_equal(&fl->fl6_src, &np->saddr) ?
+				      ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
 				      &np->saddr :
 #endif
 				      NULL);
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
new file mode 100644
index 0000000..edcfffa
--- /dev/null
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -0,0 +1,107 @@
+/*
+ * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6.
+ *
+ * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com>
+ *                    Miika Komu     <miika@iki.fi>
+ *                    Herbert Xu     <herbert@gondor.apana.org.au>
+ *                    Abhinav Pathak <abhinav.pathak@hiit.fi>
+ *                    Jeff Ahrenholz <ahrenholz@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stringify.h>
+#include <net/dsfield.h>
+#include <net/dst.h>
+#include <net/inet_ecn.h>
+#include <net/ipv6.h>
+#include <net/xfrm.h>
+
+/* Add encapsulation header.
+ *
+ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
+ * The following fields in it shall be filled in by x->type->output:
+ *	payload_len
+ *
+ * On exit, skb->h will be set to the start of the encapsulation header to be
+ * filled in by x->type->output and skb->nh will be set to the nextheader field
+ * of the extension header directly preceding the encapsulation header, or in
+ * its absence, that of the top IP header.  The value of skb->data will always
+ * point to the top IP header.
+ */
+static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct ipv6hdr *iph, *top_iph;
+	u8 *prevhdr;
+	int hdr_len;
+
+	skb_push(skb, x->props.header_len);
+	iph = skb->nh.ipv6h;
+
+	hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
+	skb->nh.raw = prevhdr - x->props.header_len;
+	skb->h.raw = skb->data + hdr_len;
+	memmove(skb->data, iph, hdr_len);
+
+	skb->nh.raw = skb->data;
+	top_iph = skb->nh.ipv6h;
+	skb->nh.raw = &top_iph->nexthdr;
+	skb->h.ipv6h = top_iph + 1;
+
+	ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
+	ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+
+	return 0;
+}
+
+static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct ipv6hdr *ip6h;
+	int size = sizeof(struct ipv6hdr);
+	int err = -EINVAL;
+
+	if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+		goto out;
+
+	skb_push(skb, size);
+	memmove(skb->data, skb->nh.raw, size);
+	skb->nh.raw = skb->data;
+
+	skb->mac.raw = memmove(skb->data - skb->mac_len,
+			       skb->mac.raw, skb->mac_len);
+
+	ip6h = skb->nh.ipv6h;
+	ip6h->payload_len = htons(skb->len - size);
+	ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
+	ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
+	err = 0;
+out:
+	return err;
+}
+
+static struct xfrm_mode xfrm6_beet_mode = {
+	.input = xfrm6_beet_input,
+	.output = xfrm6_beet_output,
+	.owner = THIS_MODULE,
+	.encap = XFRM_MODE_BEET,
+};
+
+static int __init xfrm6_beet_init(void)
+{
+	return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
+}
+
+static void __exit xfrm6_beet_exit(void)
+{
+	int err;
+
+	err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6);
+	BUG_ON(err);
+}
+
+module_init(xfrm6_beet_init);
+module_exit(xfrm6_beet_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET);
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 0a28d2c..ce94732 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -365,7 +365,7 @@
 
 config NETFILTER_XT_MATCH_PHYSDEV
 	tristate '"physdev" match support'
-	depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
+	depends on NETFILTER_XTABLES && BRIDGE && BRIDGE_NETFILTER
 	help
 	  Physdev packet matching matches against the physical bridge ports
 	  the IP packet arrived on or will leave by.
diff --git a/net/sched/estimator.c b/net/sched/estimator.c
deleted file mode 100644
index 0ebc98e..0000000
--- a/net/sched/estimator.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * net/sched/estimator.c	Simple rate estimator.
- *
- *		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:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- */
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.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/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
-#include <linux/init.h>
-#include <net/sock.h>
-#include <net/pkt_sched.h>
-
-/*
-   This code is NOT intended to be used for statistics collection,
-   its purpose is to provide a base for statistical multiplexing
-   for controlled load service.
-   If you need only statistics, run a user level daemon which
-   periodically reads byte counters.
-
-   Unfortunately, rate estimation is not a very easy task.
-   F.e. I did not find a simple way to estimate the current peak rate
-   and even failed to formulate the problem 8)8)
-
-   So I preferred not to built an estimator into the scheduler,
-   but run this task separately.
-   Ideally, it should be kernel thread(s), but for now it runs
-   from timers, which puts apparent top bounds on the number of rated
-   flows, has minimal overhead on small, but is enough
-   to handle controlled load service, sets of aggregates.
-
-   We measure rate over A=(1<<interval) seconds and evaluate EWMA:
-
-   avrate = avrate*(1-W) + rate*W
-
-   where W is chosen as negative power of 2: W = 2^(-ewma_log)
-
-   The resulting time constant is:
-
-   T = A/(-ln(1-W))
-
-
-   NOTES.
-
-   * The stored value for avbps is scaled by 2^5, so that maximal
-     rate is ~1Gbit, avpps is scaled by 2^10.
-
-   * Minimal interval is HZ/4=250msec (it is the greatest common divisor
-     for HZ=100 and HZ=1024 8)), maximal interval
-     is (HZ*2^EST_MAX_INTERVAL)/4 = 8sec. Shorter intervals
-     are too expensive, longer ones can be implemented
-     at user level painlessly.
- */
-
-#define EST_MAX_INTERVAL	5
-
-struct qdisc_estimator
-{
-	struct qdisc_estimator	*next;
-	struct tc_stats		*stats;
-	spinlock_t		*stats_lock;
-	unsigned		interval;
-	int			ewma_log;
-	u64			last_bytes;
-	u32			last_packets;
-	u32			avpps;
-	u32			avbps;
-};
-
-struct qdisc_estimator_head
-{
-	struct timer_list	timer;
-	struct qdisc_estimator	*list;
-};
-
-static struct qdisc_estimator_head elist[EST_MAX_INTERVAL+1];
-
-/* Estimator array lock */
-static DEFINE_RWLOCK(est_lock);
-
-static void est_timer(unsigned long arg)
-{
-	int idx = (int)arg;
-	struct qdisc_estimator *e;
-
-	read_lock(&est_lock);
-	for (e = elist[idx].list; e; e = e->next) {
-		struct tc_stats *st = e->stats;
-		u64 nbytes;
-		u32 npackets;
-		u32 rate;
-
-		spin_lock(e->stats_lock);
-		nbytes = st->bytes;
-		npackets = st->packets;
-		rate = (nbytes - e->last_bytes)<<(7 - idx);
-		e->last_bytes = nbytes;
-		e->avbps += ((long)rate - (long)e->avbps) >> e->ewma_log;
-		st->bps = (e->avbps+0xF)>>5;
-
-		rate = (npackets - e->last_packets)<<(12 - idx);
-		e->last_packets = npackets;
-		e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
-		e->stats->pps = (e->avpps+0x1FF)>>10;
-		spin_unlock(e->stats_lock);
-	}
-
-	mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
-	read_unlock(&est_lock);
-}
-
-int qdisc_new_estimator(struct tc_stats *stats, spinlock_t *stats_lock, struct rtattr *opt)
-{
-	struct qdisc_estimator *est;
-	struct tc_estimator *parm = RTA_DATA(opt);
-
-	if (RTA_PAYLOAD(opt) < sizeof(*parm))
-		return -EINVAL;
-
-	if (parm->interval < -2 || parm->interval > 3)
-		return -EINVAL;
-
-	est = kzalloc(sizeof(*est), GFP_KERNEL);
-	if (est == NULL)
-		return -ENOBUFS;
-
-	est->interval = parm->interval + 2;
-	est->stats = stats;
-	est->stats_lock = stats_lock;
-	est->ewma_log = parm->ewma_log;
-	est->last_bytes = stats->bytes;
-	est->avbps = stats->bps<<5;
-	est->last_packets = stats->packets;
-	est->avpps = stats->pps<<10;
-
-	est->next = elist[est->interval].list;
-	if (est->next == NULL) {
-		init_timer(&elist[est->interval].timer);
-		elist[est->interval].timer.data = est->interval;
-		elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
-		elist[est->interval].timer.function = est_timer;
-		add_timer(&elist[est->interval].timer);
-	}
-	write_lock_bh(&est_lock);
-	elist[est->interval].list = est;
-	write_unlock_bh(&est_lock);
-	return 0;
-}
-
-void qdisc_kill_estimator(struct tc_stats *stats)
-{
-	int idx;
-	struct qdisc_estimator *est, **pest;
-
-	for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
-		int killed = 0;
-		pest = &elist[idx].list;
-		while ((est=*pest) != NULL) {
-			if (est->stats != stats) {
-				pest = &est->next;
-				continue;
-			}
-
-			write_lock_bh(&est_lock);
-			*pest = est->next;
-			write_unlock_bh(&est_lock);
-
-			kfree(est);
-			killed++;
-		}
-		if (killed && elist[idx].list == NULL)
-			del_timer(&elist[idx].timer);
-	}
-}
-
-EXPORT_SYMBOL(qdisc_kill_estimator);
-EXPORT_SYMBOL(qdisc_new_estimator);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 6c058e3..bb3ddd4 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -391,7 +391,7 @@
 /* If this triggers, it is a bug in this code, but it need not be fatal */
 static void htb_safe_rb_erase(struct rb_node *rb, struct rb_root *root)
 {
-	if (!RB_EMPTY_NODE(rb)) {
+	if (RB_EMPTY_NODE(rb)) {
 		WARN_ON(1);
 	} else {
 		rb_erase(rb, root);
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 638c0b5..447d9ae 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -903,9 +903,9 @@
 struct gss_svc_data {
 	/* decoded gss client cred: */
 	struct rpc_gss_wire_cred	clcred;
-	/* pointer to the beginning of the procedure-specific results,
-	 * which may be encrypted/checksummed in svcauth_gss_release: */
-	__be32				*body_start;
+	/* save a pointer to the beginning of the encoded verifier,
+	 * for use in encryption/checksumming in svcauth_gss_release: */
+	__be32				*verf_start;
 	struct rsc			*rsci;
 };
 
@@ -968,7 +968,7 @@
 	if (!svcdata)
 		goto auth_err;
 	rqstp->rq_auth_data = svcdata;
-	svcdata->body_start = NULL;
+	svcdata->verf_start = NULL;
 	svcdata->rsci = NULL;
 	gc = &svcdata->clcred;
 
@@ -1097,6 +1097,7 @@
 		goto complete;
 	case RPC_GSS_PROC_DATA:
 		*authp = rpcsec_gsserr_ctxproblem;
+		svcdata->verf_start = resv->iov_base + resv->iov_len;
 		if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
 			goto auth_err;
 		rqstp->rq_cred = rsci->cred;
@@ -1110,7 +1111,6 @@
 					gc->gc_seq, rsci->mechctx))
 				goto auth_err;
 			/* placeholders for length and seq. number: */
-			svcdata->body_start = resv->iov_base + resv->iov_len;
 			svc_putnl(resv, 0);
 			svc_putnl(resv, 0);
 			break;
@@ -1119,7 +1119,6 @@
 					gc->gc_seq, rsci->mechctx))
 				goto auth_err;
 			/* placeholders for length and seq. number: */
-			svcdata->body_start = resv->iov_base + resv->iov_len;
 			svc_putnl(resv, 0);
 			svc_putnl(resv, 0);
 			break;
@@ -1147,6 +1146,32 @@
 	return ret;
 }
 
+u32 *
+svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd)
+{
+	u32 *p, verf_len;
+
+	p = gsd->verf_start;
+	gsd->verf_start = NULL;
+
+	/* If the reply stat is nonzero, don't wrap: */
+	if (*(p-1) != rpc_success)
+		return NULL;
+	/* Skip the verifier: */
+	p += 1;
+	verf_len = ntohl(*p++);
+	p += XDR_QUADLEN(verf_len);
+	/* move accept_stat to right place: */
+	memcpy(p, p + 2, 4);
+	/* Also don't wrap if the accept stat is nonzero: */
+	if (*p != rpc_success) {
+		resbuf->head[0].iov_len -= 2 * 4;
+		return NULL;
+	}
+	p++;
+	return p;
+}
+
 static inline int
 svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
 {
@@ -1160,17 +1185,9 @@
 	int integ_offset, integ_len;
 	int stat = -EINVAL;
 
-	p = gsd->body_start;
-	gsd->body_start = NULL;
-	/* move accept_stat to right place: */
-	memcpy(p, p + 2, 4);
-	/* Don't wrap in failure case: */
-	/* Counting on not getting here if call was not even accepted! */
-	if (*p != rpc_success) {
-		resbuf->head[0].iov_len -= 2 * 4;
+	p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+	if (p == NULL)
 		goto out;
-	}
-	p++;
 	integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
 	integ_len = resbuf->len - integ_offset;
 	BUG_ON(integ_len % 4);
@@ -1191,7 +1208,6 @@
 		resbuf->tail[0].iov_base = resbuf->head[0].iov_base
 						+ resbuf->head[0].iov_len;
 		resbuf->tail[0].iov_len = 0;
-		rqstp->rq_restailpage = 0;
 		resv = &resbuf->tail[0];
 	} else {
 		resv = &resbuf->tail[0];
@@ -1223,24 +1239,16 @@
 	int offset;
 	int pad;
 
-	p = gsd->body_start;
-	gsd->body_start = NULL;
-	/* move accept_stat to right place: */
-	memcpy(p, p + 2, 4);
-	/* Don't wrap in failure case: */
-	/* Counting on not getting here if call was not even accepted! */
-	if (*p != rpc_success) {
-		resbuf->head[0].iov_len -= 2 * 4;
+	p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+	if (p == NULL)
 		return 0;
-	}
-	p++;
 	len = p++;
 	offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
 	*p++ = htonl(gc->gc_seq);
 	inpages = resbuf->pages;
 	/* XXX: Would be better to write some xdr helper functions for
 	 * nfs{2,3,4}xdr.c that place the data right, instead of copying: */
-	if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) {
+	if (resbuf->tail[0].iov_base) {
 		BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
 							+ PAGE_SIZE);
 		BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
@@ -1258,7 +1266,6 @@
 		resbuf->tail[0].iov_base = resbuf->head[0].iov_base
 			+ resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
 		resbuf->tail[0].iov_len = 0;
-		rqstp->rq_restailpage = 0;
 	}
 	if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
 		return -ENOMEM;
@@ -1282,7 +1289,7 @@
 	if (gc->gc_proc != RPC_GSS_PROC_DATA)
 		goto out;
 	/* Release can be called twice, but we only wrap once. */
-	if (gsd->body_start == NULL)
+	if (gsd->verf_start == NULL)
 		goto out;
 	/* normally not set till svc_send, but we need it here: */
 	/* XXX: what for?  Do we mess it up the moment we call svc_putu32
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index a99e67b..c2c8bb2 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -417,18 +417,15 @@
 	if (size > RPCSVC_MAXPAYLOAD)
 		size = RPCSVC_MAXPAYLOAD;
 	pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE;
-	rqstp->rq_argused = 0;
-	rqstp->rq_resused = 0;
 	arghi = 0;
 	BUG_ON(pages > RPCSVC_MAXPAGES);
 	while (pages) {
 		struct page *p = alloc_page(GFP_KERNEL);
 		if (!p)
 			break;
-		rqstp->rq_argpages[arghi++] = p;
+		rqstp->rq_pages[arghi++] = p;
 		pages--;
 	}
-	rqstp->rq_arghi = arghi;
 	return ! pages;
 }
 
@@ -438,14 +435,10 @@
 static void
 svc_release_buffer(struct svc_rqst *rqstp)
 {
-	while (rqstp->rq_arghi)
-		put_page(rqstp->rq_argpages[--rqstp->rq_arghi]);
-	while (rqstp->rq_resused) {
-		if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
-			continue;
-		put_page(rqstp->rq_respages[rqstp->rq_resused]);
-	}
-	rqstp->rq_argused = 0;
+	int i;
+	for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
+		if (rqstp->rq_pages[i])
+			put_page(rqstp->rq_pages[i]);
 }
 
 /*
@@ -651,23 +644,32 @@
 	unsigned long		flags;
 	int			i, error = 0, dummy;
 
-	progp = serv->sv_program;
-
-	dprintk("RPC: svc_register(%s, %s, %d)\n",
-		progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
-
 	if (!port)
 		clear_thread_flag(TIF_SIGPENDING);
 
-	for (i = 0; i < progp->pg_nvers; i++) {
-		if (progp->pg_vers[i] == NULL)
-			continue;
-		error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
-		if (error < 0)
-			break;
-		if (port && !dummy) {
-			error = -EACCES;
-			break;
+	for (progp = serv->sv_program; progp; progp = progp->pg_next) {
+		for (i = 0; i < progp->pg_nvers; i++) {
+			if (progp->pg_vers[i] == NULL)
+				continue;
+
+			dprintk("RPC: svc_register(%s, %s, %d, %d)%s\n",
+					progp->pg_name,
+					proto == IPPROTO_UDP?  "udp" : "tcp",
+					port,
+					i,
+					progp->pg_vers[i]->vs_hidden?
+						" (but not telling portmap)" : "");
+
+			if (progp->pg_vers[i]->vs_hidden)
+				continue;
+
+			error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
+			if (error < 0)
+				break;
+			if (port && !dummy) {
+				error = -EACCES;
+				break;
+			}
 		}
 	}
 
@@ -697,7 +699,7 @@
 	u32			dir, prog, vers, proc;
 	__be32			auth_stat, rpc_stat;
 	int			auth_res;
-	__be32			*accept_statp;
+	__be32			*reply_statp;
 
 	rpc_stat = rpc_success;
 
@@ -707,10 +709,10 @@
 	/* setup response xdr_buf.
 	 * Initially it has just one page 
 	 */
-	svc_take_page(rqstp); /* must succeed */
+	rqstp->rq_resused = 1;
 	resv->iov_base = page_address(rqstp->rq_respages[0]);
 	resv->iov_len = 0;
-	rqstp->rq_res.pages = rqstp->rq_respages+1;
+	rqstp->rq_res.pages = rqstp->rq_respages + 1;
 	rqstp->rq_res.len = 0;
 	rqstp->rq_res.page_base = 0;
 	rqstp->rq_res.page_len = 0;
@@ -738,7 +740,7 @@
 		goto err_bad_rpc;
 
 	/* Save position in case we later decide to reject: */
-	accept_statp = resv->iov_base + resv->iov_len;
+	reply_statp = resv->iov_base + resv->iov_len;
 
 	svc_putnl(resv, 0);		/* ACCEPT */
 
@@ -886,7 +888,7 @@
 	dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
 	serv->sv_stats->rpcbadauth++;
 	/* Restore write pointer to location of accept status: */
-	xdr_ressize_check(rqstp, accept_statp);
+	xdr_ressize_check(rqstp, reply_statp);
 	svc_putnl(resv, 1);	/* REJECT */
 	svc_putnl(resv, 1);	/* AUTH_ERROR */
 	svc_putnl(resv, ntohl(auth_stat));	/* status */
@@ -926,3 +928,18 @@
 	svc_putnl(resv, ntohl(rpc_stat));
 	goto sendit;
 }
+
+/*
+ * Return (transport-specific) limit on the rpc payload.
+ */
+u32 svc_max_payload(const struct svc_rqst *rqstp)
+{
+	int max = RPCSVC_MAXPAYLOAD_TCP;
+
+	if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM)
+		max = RPCSVC_MAXPAYLOAD_UDP;
+	if (rqstp->rq_server->sv_bufsz < max)
+		max = rqstp->rq_server->sv_bufsz;
+	return max;
+}
+EXPORT_SYMBOL_GPL(svc_max_payload);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 40d41a2..e1bd933 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -9,6 +9,7 @@
 #include <linux/seq_file.h>
 #include <linux/hash.h>
 #include <linux/string.h>
+#include <net/sock.h>
 
 #define RPCDBG_FACILITY	RPCDBG_AUTH
 
@@ -375,6 +376,44 @@
 	cache_purge(&ip_map_cache);
 }
 
+static inline struct ip_map *
+ip_map_cached_get(struct svc_rqst *rqstp)
+{
+	struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix;
+	if (ipm != NULL) {
+		if (!cache_valid(&ipm->h)) {
+			/*
+			 * The entry has been invalidated since it was
+			 * remembered, e.g. by a second mount from the
+			 * same IP address.
+			 */
+			rqstp->rq_sock->sk_info_authunix = NULL;
+			cache_put(&ipm->h, &ip_map_cache);
+			return NULL;
+		}
+		cache_get(&ipm->h);
+	}
+	return ipm;
+}
+
+static inline void
+ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
+{
+	struct svc_sock *svsk = rqstp->rq_sock;
+
+	if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL)
+		svsk->sk_info_authunix = ipm;	/* newly cached, keep the reference */
+	else
+		cache_put(&ipm->h, &ip_map_cache);
+}
+
+void
+svcauth_unix_info_release(void *info)
+{
+	struct ip_map *ipm = info;
+	cache_put(&ipm->h, &ip_map_cache);
+}
+
 static int
 svcauth_unix_set_client(struct svc_rqst *rqstp)
 {
@@ -384,8 +423,10 @@
 	if (rqstp->rq_proc == 0)
 		return SVC_OK;
 
-	ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
-			    rqstp->rq_addr.sin_addr);
+	ipm = ip_map_cached_get(rqstp);
+	if (ipm == NULL)
+		ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
+				    rqstp->rq_addr.sin_addr);
 
 	if (ipm == NULL)
 		return SVC_DENIED;
@@ -400,7 +441,7 @@
 		case 0:
 			rqstp->rq_client = &ipm->m_client->h;
 			kref_get(&rqstp->rq_client->ref);
-			cache_put(&ipm->h, &ip_map_cache);
+			ip_map_cached_put(rqstp, ipm);
 			break;
 	}
 	return SVC_OK;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index cba85d1..b39e7e2 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -313,7 +313,7 @@
 
 	svc_release_skb(rqstp);
 
-	svc_free_allpages(rqstp);
+	svc_free_res_pages(rqstp);
 	rqstp->rq_res.page_len = 0;
 	rqstp->rq_res.page_base = 0;
 
@@ -412,7 +412,8 @@
 	/* send head */
 	if (slen == xdr->head[0].iov_len)
 		flags = 0;
-	len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags);
+	len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
+				  xdr->head[0].iov_len, flags);
 	if (len != xdr->head[0].iov_len)
 		goto out;
 	slen -= xdr->head[0].iov_len;
@@ -437,8 +438,9 @@
 	}
 	/* send tail */
 	if (xdr->tail[0].iov_len) {
-		result = kernel_sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage],
-					     ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1),
+		result = kernel_sendpage(sock, rqstp->rq_respages[0],
+					     ((unsigned long)xdr->tail[0].iov_base)
+					        & (PAGE_SIZE-1),
 					     xdr->tail[0].iov_len, 0);
 
 		if (result > 0)
@@ -492,7 +494,12 @@
 	}
 	spin_unlock(&serv->sv_lock);
 	if (closesk)
+		/* Should unregister with portmap, but you cannot
+		 * unregister just one protocol...
+		 */
 		svc_delete_socket(closesk);
+	else if (toclose)
+		return -ENOENT;
 	return len;
 }
 EXPORT_SYMBOL(svc_sock_names);
@@ -703,9 +710,11 @@
 	if (len <= rqstp->rq_arg.head[0].iov_len) {
 		rqstp->rq_arg.head[0].iov_len = len;
 		rqstp->rq_arg.page_len = 0;
+		rqstp->rq_respages = rqstp->rq_pages+1;
 	} else {
 		rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
-		rqstp->rq_argused += (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
+		rqstp->rq_respages = rqstp->rq_pages + 1 +
+			(rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
 	}
 
 	if (serv->sv_stats)
@@ -946,7 +955,7 @@
 	struct svc_sock	*svsk = rqstp->rq_sock;
 	struct svc_serv	*serv = svsk->sk_server;
 	int		len;
-	struct kvec vec[RPCSVC_MAXPAGES];
+	struct kvec *vec;
 	int pnum, vlen;
 
 	dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
@@ -1044,15 +1053,17 @@
 	len = svsk->sk_reclen;
 	set_bit(SK_DATA, &svsk->sk_flags);
 
+	vec = rqstp->rq_vec;
 	vec[0] = rqstp->rq_arg.head[0];
 	vlen = PAGE_SIZE;
 	pnum = 1;
 	while (vlen < len) {
-		vec[pnum].iov_base = page_address(rqstp->rq_argpages[rqstp->rq_argused++]);
+		vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]);
 		vec[pnum].iov_len = PAGE_SIZE;
 		pnum++;
 		vlen += PAGE_SIZE;
 	}
+	rqstp->rq_respages = &rqstp->rq_pages[pnum];
 
 	/* Now receive data */
 	len = svc_recvfrom(rqstp, vec, pnum, len);
@@ -1204,7 +1215,7 @@
 	struct svc_sock		*svsk =NULL;
 	struct svc_serv		*serv = rqstp->rq_server;
 	struct svc_pool		*pool = rqstp->rq_pool;
-	int			len;
+	int			len, i;
 	int 			pages;
 	struct xdr_buf		*arg;
 	DECLARE_WAITQUEUE(wait, current);
@@ -1221,27 +1232,22 @@
 			"svc_recv: service %p, wait queue active!\n",
 			 rqstp);
 
-	/* Initialize the buffers */
-	/* first reclaim pages that were moved to response list */
-	svc_pushback_allpages(rqstp);
 
 	/* now allocate needed pages.  If we get a failure, sleep briefly */
 	pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE;
-	while (rqstp->rq_arghi < pages) {
-		struct page *p = alloc_page(GFP_KERNEL);
-		if (!p) {
-			schedule_timeout_uninterruptible(msecs_to_jiffies(500));
-			continue;
+	for (i=0; i < pages ; i++)
+		while (rqstp->rq_pages[i] == NULL) {
+			struct page *p = alloc_page(GFP_KERNEL);
+			if (!p)
+				schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+			rqstp->rq_pages[i] = p;
 		}
-		rqstp->rq_argpages[rqstp->rq_arghi++] = p;
-	}
 
 	/* Make arg->head point to first page and arg->pages point to rest */
 	arg = &rqstp->rq_arg;
-	arg->head[0].iov_base = page_address(rqstp->rq_argpages[0]);
+	arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
 	arg->head[0].iov_len = PAGE_SIZE;
-	rqstp->rq_argused = 1;
-	arg->pages = rqstp->rq_argpages + 1;
+	arg->pages = rqstp->rq_pages + 1;
 	arg->page_base = 0;
 	/* save at least one page for response */
 	arg->page_len = (pages-2)*PAGE_SIZE;
@@ -1604,6 +1610,8 @@
 			sockfd_put(svsk->sk_sock);
 		else
 			sock_release(svsk->sk_sock);
+		if (svsk->sk_info_authunix != NULL)
+			svcauth_unix_info_release(svsk->sk_info_authunix);
 		kfree(svsk);
 	} else {
 		spin_unlock_bh(&serv->sv_lock);
@@ -1699,6 +1707,7 @@
 	rqstp->rq_prot        = dr->prot;
 	rqstp->rq_addr        = dr->addr;
 	rqstp->rq_daddr       = dr->daddr;
+	rqstp->rq_respages    = rqstp->rq_pages;
 	return dr->argslen<<2;
 }
 
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 693f02e..53bc8cb 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -1666,8 +1666,9 @@
 		char addr_string[16];
 
 		tipc_printf(TIPC_OUTPUT, "Msg seq number: %u,  ", msg_seqno(msg));
-		tipc_printf(TIPC_OUTPUT, "Outstanding acks: %u\n", (u32)TIPC_SKB_CB(buf)->handle);
-		
+		tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n",
+				     (unsigned long) TIPC_SKB_CB(buf)->handle);
+
 		n_ptr = l_ptr->owner->next;
 		tipc_node_lock(n_ptr);
 
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index 6ac4e4f..d401dc8 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -41,17 +41,18 @@
 	return (h ^ (h >> 16)) & hmask;
 }
 
-static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr,
+static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
+				       xfrm_address_t *saddr,
 				       unsigned short family,
 				       unsigned int hmask)
 {
 	unsigned int h = family;
 	switch (family) {
 	case AF_INET:
-		h ^= __xfrm4_addr_hash(saddr);
+		h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
 		break;
 	case AF_INET6:
-		h ^= __xfrm6_addr_hash(saddr);
+		h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
 		break;
 	};
 	return (h ^ (h >> 16)) & hmask;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b6e2e79..2a78616 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -778,8 +778,9 @@
 	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
 		struct xfrm_policy *pol;
 		struct hlist_node *entry;
-		int i;
+		int i, killed;
 
+		killed = 0;
 	again1:
 		hlist_for_each_entry(pol, entry,
 				     &xfrm_policy_inexact[dir], bydst) {
@@ -790,6 +791,7 @@
 			write_unlock_bh(&xfrm_policy_lock);
 
 			xfrm_policy_kill(pol);
+			killed++;
 
 			write_lock_bh(&xfrm_policy_lock);
 			goto again1;
@@ -807,13 +809,14 @@
 				write_unlock_bh(&xfrm_policy_lock);
 
 				xfrm_policy_kill(pol);
+				killed++;
 
 				write_lock_bh(&xfrm_policy_lock);
 				goto again2;
 			}
 		}
 
-		xfrm_policy_count[dir] = 0;
+		xfrm_policy_count[dir] -= killed;
 	}
 	atomic_inc(&flow_cache_genid);
 	write_unlock_bh(&xfrm_policy_lock);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index f927b73..39b8bf3 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -63,10 +63,11 @@
 	return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
 }
 
-static inline unsigned int xfrm_src_hash(xfrm_address_t *addr,
+static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
+					 xfrm_address_t *saddr,
 					 unsigned short family)
 {
-	return __xfrm_src_hash(addr, family, xfrm_state_hmask);
+	return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
 }
 
 static inline unsigned int
@@ -92,7 +93,8 @@
 				    nhashmask);
 		hlist_add_head(&x->bydst, ndsttable+h);
 
-		h = __xfrm_src_hash(&x->props.saddr, x->props.family,
+		h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
+				    x->props.family,
 				    nhashmask);
 		hlist_add_head(&x->bysrc, nsrctable+h);
 
@@ -458,7 +460,7 @@
 
 static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
 {
-	unsigned int h = xfrm_src_hash(saddr, family);
+	unsigned int h = xfrm_src_hash(daddr, saddr, family);
 	struct xfrm_state *x;
 	struct hlist_node *entry;
 
@@ -587,7 +589,7 @@
 		if (km_query(x, tmpl, pol) == 0) {
 			x->km.state = XFRM_STATE_ACQ;
 			hlist_add_head(&x->bydst, xfrm_state_bydst+h);
-			h = xfrm_src_hash(saddr, family);
+			h = xfrm_src_hash(daddr, saddr, family);
 			hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
 			if (x->id.spi) {
 				h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
@@ -622,7 +624,7 @@
 			  x->props.reqid, x->props.family);
 	hlist_add_head(&x->bydst, xfrm_state_bydst+h);
 
-	h = xfrm_src_hash(&x->props.saddr, x->props.family);
+	h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
 	hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
 
 	if (x->id.spi) {
@@ -748,7 +750,7 @@
 		x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
 		add_timer(&x->timer);
 		hlist_add_head(&x->bydst, xfrm_state_bydst+h);
-		h = xfrm_src_hash(saddr, family);
+		h = xfrm_src_hash(daddr, saddr, family);
 		hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
 		wake_up(&km_waitq);
 	}
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index c59a78d..d54b3a7 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -211,6 +211,7 @@
 	case XFRM_MODE_TRANSPORT:
 	case XFRM_MODE_TUNNEL:
 	case XFRM_MODE_ROUTEOPTIMIZATION:
+	case XFRM_MODE_BEET:
 		break;
 
 	default:
diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
index cac8f21..6a026f6 100644
--- a/scripts/Makefile.headersinst
+++ b/scripts/Makefile.headersinst
@@ -97,7 +97,7 @@
 				   | $(HDRSED) > $@ || :
 
 quiet_cmd_check		  = CHECK   $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/.check.%,$(_dst)/%,$@)
-      cmd_check		  = $(srctree)/scripts/hdrcheck.sh		\
+      cmd_check		  = $(CONFIG_SHELL) $(srctree)/scripts/hdrcheck.sh \
                               $(INSTALL_HDR_PATH)/include $(subst /.check.,/,$@) $@
 
 quiet_cmd_remove	  = REMOVE  $(_dst)/$@
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
index d31f814..f580942 100644
--- a/sound/aoa/soundbus/sysfs.c
+++ b/sound/aoa/soundbus/sysfs.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/stat.h>
 /* FIX UP */
diff --git a/sound/core/memory.c b/sound/core/memory.c
index fe59850..93537ab 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -20,7 +20,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 8681179..2489bd6 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -15,71 +15,42 @@
 obj-$(CONFIG_SOUND_AEDSP16)	+= aedsp16.o
 obj-$(CONFIG_SOUND_PSS)		+= pss.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_TRIX)	+= trix.o ad1848.o sb_lib.o uart401.o
-obj-$(CONFIG_SOUND_OPL3SA1)	+= opl3sa.o ad1848.o uart401.o
 obj-$(CONFIG_SOUND_SSCAPE)	+= sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_MAD16)	+= mad16.o ad1848.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_CS4232)	+= cs4232.o uart401.o
 obj-$(CONFIG_SOUND_MSS)		+= ad1848.o
 obj-$(CONFIG_SOUND_OPL3SA2)	+= opl3sa2.o ad1848.o mpu401.o
 obj-$(CONFIG_SOUND_PAS)		+= pas2.o sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_SB)		+= sb.o sb_lib.o uart401.o
 obj-$(CONFIG_SOUND_KAHLUA)	+= kahlua.o
-obj-$(CONFIG_SOUND_WAVEFRONT)	+= wavefront.o
-obj-$(CONFIG_SOUND_MAUI)	+= maui.o mpu401.o
 obj-$(CONFIG_SOUND_MPU401)	+= mpu401.o
 obj-$(CONFIG_SOUND_UART6850)	+= uart6850.o
-obj-$(CONFIG_SOUND_GUS)		+= gus.o ad1848.o
 obj-$(CONFIG_SOUND_ADLIB)	+= adlib_card.o opl3.o
 obj-$(CONFIG_SOUND_YM3812)	+= opl3.o
 obj-$(CONFIG_SOUND_VMIDI)	+= v_midi.o
 obj-$(CONFIG_SOUND_VIDC)	+= vidc_mod.o
 obj-$(CONFIG_SOUND_WAVEARTIST)	+= waveartist.o
-obj-$(CONFIG_SOUND_SGALAXY)	+= sgalaxy.o ad1848.o
 obj-$(CONFIG_SOUND_AD1816)	+= ad1816.o
 obj-$(CONFIG_SOUND_AD1889)	+= ad1889.o ac97_codec.o
 obj-$(CONFIG_SOUND_ACI_MIXER)	+= aci.o
-obj-$(CONFIG_SOUND_AWE32_SYNTH)	+= awe_wave.o
 
 obj-$(CONFIG_SOUND_VIA82CXXX)	+= via82cxxx_audio.o ac97_codec.o
 ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
   obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o
 endif
-obj-$(CONFIG_SOUND_YMFPCI)	+= ymfpci.o ac97_codec.o
-ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y)
-  obj-$(CONFIG_SOUND_YMFPCI)    += opl3.o uart401.o
-endif
 obj-$(CONFIG_SOUND_MSNDCLAS)	+= msnd.o msnd_classic.o
 obj-$(CONFIG_SOUND_MSNDPIN)	+= msnd.o msnd_pinnacle.o
 obj-$(CONFIG_SOUND_VWSND)	+= vwsnd.o
 obj-$(CONFIG_SOUND_NM256)	+= nm256_audio.o ac97.o
 obj-$(CONFIG_SOUND_ICH)		+= i810_audio.o ac97_codec.o
-obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
-obj-$(CONFIG_SOUND_CMPCI)	+= cmpci.o
-ifeq ($(CONFIG_SOUND_CMPCI_FM),y)
-  obj-$(CONFIG_SOUND_CMPCI)     += sound.o opl3.o
-endif
-ifeq ($(CONFIG_SOUND_CMPCI_MIDI),y)
-  obj-$(CONFIG_SOUND_CMPCI)     += sound.o mpu401.o
-endif
-obj-$(CONFIG_SOUND_ES1370)	+= es1370.o
 obj-$(CONFIG_SOUND_ES1371)	+= es1371.o ac97_codec.o
 obj-$(CONFIG_SOUND_VRC5477)	+= nec_vrc5477.o ac97_codec.o
-obj-$(CONFIG_SOUND_AU1000)	+= au1000.o ac97_codec.o
 obj-$(CONFIG_SOUND_AU1550_AC97)	+= au1550_ac97.o ac97_codec.o
-obj-$(CONFIG_SOUND_ESSSOLO1)	+= esssolo1.o
 obj-$(CONFIG_SOUND_FUSION)	+= cs46xx.o ac97_codec.o
-obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
-obj-$(CONFIG_SOUND_MAESTRO3)	+= maestro3.o ac97_codec.o
 obj-$(CONFIG_SOUND_TRIDENT)	+= trident.o ac97_codec.o
-obj-$(CONFIG_SOUND_HARMONY)	+= harmony.o
 obj-$(CONFIG_SOUND_EMU10K1)	+= ac97_codec.o
 obj-$(CONFIG_SOUND_BCM_CS4297A)	+= swarm_cs4297a.o
-obj-$(CONFIG_SOUND_RME96XX)     += rme96xx.o
 obj-$(CONFIG_SOUND_BT878)	+= btaudio.o
-obj-$(CONFIG_SOUND_ALI5455)	+= ali5455.o ac97_codec.o
-obj-$(CONFIG_SOUND_FORTE)	+= forte.o ac97_codec.o
 
-obj-$(CONFIG_SOUND_AD1980)	+= ac97_plugin_ad1980.o ac97_codec.o
 obj-$(CONFIG_SOUND_WM97XX)	+= ac97_plugin_wm97xx.o
 
 ifeq ($(CONFIG_MIDI_EMU10K1),y)
@@ -87,28 +58,25 @@
 endif
 
 obj-$(CONFIG_SOUND_EMU10K1)	+= emu10k1/
-obj-$(CONFIG_SOUND_CS4281)	+= cs4281/
 obj-$(CONFIG_DMASOUND)		+= dmasound/
 
 # Declare multi-part drivers.
 
 sound-objs	:= 							\
-    dev_table.o soundcard.o sound_syms.o		\
-    audio.o audio_syms.o dmabuf.o					\
-    midi_syms.o midi_synth.o midibuf.o					\
-    sequencer.o sequencer_syms.o sound_timer.o sys_timer.o
+    dev_table.o soundcard.o 		\
+    audio.o dmabuf.o					\
+    midi_synth.o midibuf.o					\
+    sequencer.o sound_timer.o sys_timer.o
 
-gus-objs	:= gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
 pas2-objs	:= pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
 sb-objs		:= sb_card.o
 sb_lib-objs	:= sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o
 vidc_mod-objs	:= vidc.o vidc_fill.o
-wavefront-objs  := wavfront.o wf_midi.o yss225.o
 
 hostprogs-y	:= bin2hex hex2hex
 
 # Files generated that shall be removed upon make clean
-clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \
+clean-files := msndperm.c msndinit.c pndsperm.c pndspini.c \
                pss_boot.h trix_boot.h
 
 # Firmware files that need translation
@@ -118,21 +86,6 @@
 # will be forced to be remade.
 #
 
-# Turtle Beach Maui / Tropez
-
-$(obj)/maui.o: $(obj)/maui_boot.h
-
-ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
-    $(obj)/maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) $(obj)/bin2hex
-	$(obj)/bin2hex -i maui_os < $< > $@
-else
-    $(obj)/maui_boot.h:
-	(							\
-	    echo 'static unsigned char * maui_os = NULL;';	\
-	    echo 'static int maui_osLen = 0;';			\
-	) > $@
-endif
-
 # Turtle Beach MultiSound
 
 ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y)
diff --git a/sound/oss/ac97.c b/sound/oss/ac97.c
index 3ba6d91..72cf4ed 100644
--- a/sound/oss/ac97.c
+++ b/sound/oss/ac97.c
@@ -112,25 +112,6 @@
     return 0;
 }
 
-/* Reset the mixer to the currently saved settings.  */
-int
-ac97_reset (struct ac97_hwint *dev)
-{
-    int x;
-
-    if (dev->reset_device (dev))
-	return -1;
-
-    /* Now set the registers back to their last-written values. */
-    for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
-	int regnum = mixerRegs[x].ac97_regnum;
-	int value = dev->last_written_mixer_values [regnum / 2];
-	if (value >= 0)
-	    ac97_put_register (dev, regnum, value);
-    }
-    return 0;
-}
-
 /* Return the contents of register REG; use the cache if the value in it
    is valid.  Returns a negative error code on failure. */
 static int
@@ -441,7 +422,6 @@
 EXPORT_SYMBOL(ac97_set_values);
 EXPORT_SYMBOL(ac97_put_register);
 EXPORT_SYMBOL(ac97_mixer_ioctl);
-EXPORT_SYMBOL(ac97_reset);
 MODULE_LICENSE("GPL");
 
 
diff --git a/sound/oss/ac97.h b/sound/oss/ac97.h
index 77d454e..01837a9 100644
--- a/sound/oss/ac97.h
+++ b/sound/oss/ac97.h
@@ -192,9 +192,6 @@
 extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
 			     void __user * arg);
 
-/* Do a complete reset on the AC97 mixer, restoring all mixer registers to
-   the current values.  Normally used after an APM resume event.  */
-extern int ac97_reset (struct ac97_hwint *dev);
 #endif
 
 /*
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index 972327c..602db49 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -1399,95 +1399,6 @@
 
 EXPORT_SYMBOL(ac97_set_adc_rate);
 
-int ac97_save_state(struct ac97_codec *codec)
-{
-	return 0;	
-}
-
-EXPORT_SYMBOL(ac97_save_state);
-
-int ac97_restore_state(struct ac97_codec *codec)
-{
-	int i;
-	unsigned int left, right, val;
-
-	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-		if (!supported_mixer(codec, i)) 
-			continue;
-
-		val = codec->mixer_state[i];
-		right = val >> 8;
-		left = val  & 0xff;
-		codec->write_mixer(codec, i, left, right);
-	}
-	return 0;
-}
-
-EXPORT_SYMBOL(ac97_restore_state);
-
-/**
- *	ac97_register_driver	-	register a codec helper
- *	@driver: Driver handler
- *
- *	Register a handler for codecs matching the codec id. The handler
- *	attach function is called for all present codecs and will be 
- *	called when new codecs are discovered.
- */
- 
-int ac97_register_driver(struct ac97_driver *driver)
-{
-	struct list_head *l;
-	struct ac97_codec *c;
-	
-	mutex_lock(&codec_mutex);
-	INIT_LIST_HEAD(&driver->list);
-	list_add(&driver->list, &codec_drivers);
-	
-	list_for_each(l, &codecs)
-	{
-		c = list_entry(l, struct ac97_codec, list);
-		if(c->driver != NULL || ((c->model ^ driver->codec_id) & driver->codec_mask))
-			continue;
-		if(driver->probe(c, driver))
-			continue;
-		c->driver = driver;
-	}
-	mutex_unlock(&codec_mutex);
-	return 0;
-}
-
-EXPORT_SYMBOL_GPL(ac97_register_driver);
-
-/**
- *	ac97_unregister_driver	-	unregister a codec helper
- *	@driver: Driver handler
- *
- *	Unregister a handler for codecs matching the codec id. The handler
- *	remove function is called for all matching codecs.
- */
- 
-void ac97_unregister_driver(struct ac97_driver *driver)
-{
-	struct list_head *l;
-	struct ac97_codec *c;
-	
-	mutex_lock(&codec_mutex);
-	list_del_init(&driver->list);
-
-	list_for_each(l, &codecs)
-	{
-		c = list_entry(l, struct ac97_codec, list);
-		if (c->driver == driver) {
-			driver->remove(c, driver);
-			c->driver = NULL;
-		}
-	}
-	
-	mutex_unlock(&codec_mutex);
-}
-
-EXPORT_SYMBOL_GPL(ac97_unregister_driver);
-
 static int swap_headphone(int remove_master)
 {
 	struct list_head *l;
diff --git a/sound/oss/ac97_plugin_ad1980.c b/sound/oss/ac97_plugin_ad1980.c
deleted file mode 100644
index 24a9acd..0000000
--- a/sound/oss/ac97_plugin_ad1980.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
-    ac97_plugin_ad1980.c  Copyright (C) 2003 Red Hat, Inc. All rights reserved.
-
-   The contents of this file are subject to the Open Software License version 1.1
-   that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is 
-   included herein by reference. 
-   
-   Alternatively, the contents of this file may be used under the
-   terms of the GNU General Public License version 2 (the "GPL") as 
-   distributed in the kernel source COPYING file, in which
-   case the provisions of the GPL are applicable instead of the
-   above.  If you wish to allow the use of your version of this file
-   only under the terms of the GPL and not to allow others to use
-   your version of this file under the OSL, indicate your decision
-   by deleting the provisions above and replace them with the notice
-   and other provisions required by the GPL.  If you do not delete
-   the provisions above, a recipient may use your version of this
-   file under either the OSL or the GPL.
-   
-   Authors: 	Alan Cox <alan@redhat.com>
-
-   This is an example codec plugin. This one switches the connections
-   around to match the setups some vendors use with audio switched to
-   non standard front connectors not the normal rear ones
-
-   This code primarily exists to demonstrate how to use the codec
-   interface
-
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ac97_codec.h>
-
-/**
- *	ad1980_remove		-	codec remove callback
- *	@codec: The codec that is being removed
- *
- *	This callback occurs when an AC97 codec is being removed. A
- *	codec remove call will not occur for a codec during that codec
- *	probe callback.
- *
- *	Most drivers will need to lock their remove versus their 
- *	use of the codec after the probe function.
- */
- 
-static void __devexit ad1980_remove(struct ac97_codec *codec, struct ac97_driver *driver)
-{
-	/* Nothing to do in the simple example */
-}
-
-
-/**
- *	ad1980_probe		-	codec found callback
- *	@codec: ac97 codec matching the idents
- *	@driver: ac97_driver it matched
- *
- *	This entry point is called when a codec is found which matches
- *	the driver. At the point it is called the codec is basically
- *	operational, mixer operations have been initialised and can
- *	be overriden. Called in process context. The field driver_private
- *	is available for the driver to use to store stuff.
- *
- *	The caller can claim the device by returning zero, or return
- *	a negative error code. 
- */
- 
-static int ad1980_probe(struct ac97_codec *codec, struct ac97_driver *driver)
-{
-	u16 control;
-
-#define AC97_AD_MISC	0x76
-
-	/* Switch the inputs/outputs over (from Dell code) */
-	control = codec->codec_read(codec, AC97_AD_MISC);
-	codec->codec_write(codec, AC97_AD_MISC, control | 0x4420);
-	
-	/* We could refuse the device since we dont need to hang around,
-	   but we will claim it */
-	return 0;
-}
-	
- 
-static struct ac97_driver ad1980_driver = {
-	.codec_id	= 0x41445370,
-	.codec_mask	= 0xFFFFFFFF,
-	.name		= "AD1980 example",
-	.probe		= ad1980_probe,
-	.remove		= __devexit_p(ad1980_remove),
-};
-
-/**
- *	ad1980_exit		-	module exit path
- *
- *	Our module is being unloaded. At this point unregister_driver
- *	will call back our remove handler for any existing codecs. You
- *	may not unregister_driver from interrupt context or from a 
- *	probe/remove callback.
- */
-
-static void ad1980_exit(void)
-{
-	ac97_unregister_driver(&ad1980_driver);
-}
-
-/**
- *	ad1980_init		-	set up ad1980 handlers
- *
- *	After we call the register function it will call our probe
- *	function for each existing matching device before returning to us.
- *	Any devices appearing afterwards whose id's match the codec_id
- *	will also cause the probe function to be called.
- *	You may not register_driver from interrupt context or from a 
- *	probe/remove callback.
- */
- 
-static int ad1980_init(void)
-{
-	return ac97_register_driver(&ad1980_driver);
-}
-
-module_init(ad1980_init);
-module_exit(ad1980_exit);
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index f6b6b88..257b753 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -195,6 +195,7 @@
 static void     ad1848_halt_input(int dev);
 static void     ad1848_halt_output(int dev);
 static void     ad1848_trigger(int dev, int bits);
+static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy);
 
 #ifndef EXCLUDE_TIMERS
 static int ad1848_tmr_install(int dev);
@@ -2195,7 +2196,7 @@
 		printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);
 }
 
-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
 {
 	unsigned char status;
 	ad1848_info *devc;
@@ -2802,7 +2803,6 @@
 EXPORT_SYMBOL(ad1848_init);
 EXPORT_SYMBOL(ad1848_unload);
 EXPORT_SYMBOL(ad1848_control);
-EXPORT_SYMBOL(adintr);
 EXPORT_SYMBOL(probe_ms_sound);
 EXPORT_SYMBOL(attach_ms_sound);
 EXPORT_SYMBOL(unload_ms_sound);
diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h
index d0573b0..b95ebe2 100644
--- a/sound/oss/ad1848.h
+++ b/sound/oss/ad1848.h
@@ -18,7 +18,6 @@
 int ad1848_detect (struct resource *ports, int *flags, int *osp);
 int ad1848_control(int cmd, int arg);
 
-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs * dummy);
 void attach_ms_sound(struct address_info * hw_config, struct resource *ports, struct module * owner);
 
 int probe_ms_sound(struct address_info *hw_config, struct resource *ports);
diff --git a/sound/oss/ali5455.c b/sound/oss/ali5455.c
deleted file mode 100644
index 70dcd70..0000000
--- a/sound/oss/ali5455.c
+++ /dev/null
@@ -1,3735 +0,0 @@
-/*
- *	ALI  ali5455 and friends ICH driver for Linux
- *	LEI HU <Lei_Hu@ali.com.tw>
- *
- *  Built from:
- *	drivers/sound/i810_audio
- *
- *  	The ALi 5455 is similar but not quite identical to the Intel ICH
- *	series of controllers. Its easier to keep the driver separated from
- *	the i810 driver.
- *
- *	This program is free software; you can redistribute it and/or modify
- *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
- *
- *	You should have received a copy of the GNU General Public License
- *	along with this program; if not, write to the Free Software
- *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *	ALi 5455 theory of operation
- *
- *	The chipset provides three DMA channels that talk to an AC97
- *	CODEC (AC97 is a digital/analog mixer standard). At its simplest
- *	you get 48Khz audio with basic volume and mixer controls. At the
- *	best you get rate adaption in the codec. We set the card up so
- *	that we never take completion interrupts but instead keep the card
- *	chasing its tail around a ring buffer. This is needed for mmap
- *	mode audio and happens to work rather well for non-mmap modes too.
- *
- *	The board has one output channel for PCM audio (supported) and
- *	a stereo line in and mono microphone input. Again these are normally
- *	locked to 48Khz only. Right now recording is not finished.
- *
- *	There is no midi support, no synth support. Use timidity. To get
- *	esd working you need to use esd -r 48000 as it won't probe 48KHz
- *	by default. mpg123 can't handle 48Khz only audio so use xmms.
- *
- *	If you need to force a specific rate set the clocking= option
- *
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-
-#ifndef PCI_DEVICE_ID_ALI_5455
-#define PCI_DEVICE_ID_ALI_5455	0x5455
-#endif
-
-#ifndef PCI_VENDOR_ID_ALI
-#define PCI_VENDOR_ID_ALI	0x10b9
-#endif
-
-static int strict_clocking = 0;
-static unsigned int clocking = 0;
-static unsigned int codec_pcmout_share_spdif_locked = 0;
-static unsigned int codec_independent_spdif_locked = 0;
-static unsigned int controller_pcmout_share_spdif_locked = 0;
-static unsigned int controller_independent_spdif_locked = 0;
-static unsigned int globel = 0;
-
-#define ADC_RUNNING	1
-#define DAC_RUNNING	2
-#define CODEC_SPDIFOUT_RUNNING 8
-#define CONTROLLER_SPDIFOUT_RUNNING 4
-
-#define SPDIF_ENABLE_OUTPUT	4	/* bits 0,1 are PCM */
-
-#define ALI5455_FMT_16BIT	1
-#define ALI5455_FMT_STEREO	2
-#define ALI5455_FMT_MASK	3
-
-#define SPDIF_ON	0x0004
-#define SURR_ON		0x0010
-#define CENTER_LFE_ON	0x0020
-#define VOL_MUTED	0x8000
-
-
-#define ALI_SPDIF_OUT_CH_STATUS 0xbf
-/* the 810's array of pointers to data buffers */
-
-struct sg_item {
-#define BUSADDR_MASK	0xFFFFFFFE
-	u32 busaddr;
-#define CON_IOC 	0x80000000	/* interrupt on completion */
-#define CON_BUFPAD	0x40000000	/* pad underrun with last sample, else 0 */
-#define CON_BUFLEN_MASK	0x0000ffff	/* buffer length in samples */
-	u32 control;
-};
-
-/* an instance of the ali channel */
-#define SG_LEN 32
-struct ali_channel {
-	/* these sg guys should probably be allocated
-	   separately as nocache. Must be 8 byte aligned */
-	struct sg_item sg[SG_LEN];	/* 32*8 */
-	u32 offset;		/* 4 */
-	u32 port;		/* 4 */
-	u32 used;
-	u32 num;
-};
-
-/*
- * we have 3 separate dma engines.  pcm in, pcm out, and mic.
- * each dma engine has controlling registers.  These goofy
- * names are from the datasheet, but make it easy to write
- * code while leafing through it.
- */
-
-#define ENUM_ENGINE(PRE,DIG) 									\
-enum {												\
-	PRE##_BDBAR =	0x##DIG##0,		/* Buffer Descriptor list Base Address */	\
-	PRE##_CIV =	0x##DIG##4,		/* Current Index Value */			\
-	PRE##_LVI =	0x##DIG##5,		/* Last Valid Index */				\
-	PRE##_SR =	0x##DIG##6,		/* Status Register */				\
-	PRE##_PICB =	0x##DIG##8,		/* Position In Current Buffer */		\
-	PRE##_CR =	0x##DIG##b		/* Control Register */				\
-}
-
-ENUM_ENGINE(OFF, 0);		/* Offsets */
-ENUM_ENGINE(PI, 4);		/* PCM In */
-ENUM_ENGINE(PO, 5);		/* PCM Out */
-ENUM_ENGINE(MC, 6);		/* Mic In */
-ENUM_ENGINE(CODECSPDIFOUT, 7);	/* CODEC SPDIF OUT  */
-ENUM_ENGINE(CONTROLLERSPDIFIN, A);	/* CONTROLLER SPDIF In */
-ENUM_ENGINE(CONTROLLERSPDIFOUT, B);	/* CONTROLLER SPDIF OUT */
-
-
-enum {
-	ALI_SCR = 0x00,		/* System Control Register */
-	ALI_SSR = 0x04,		/* System Status Register  */
-	ALI_DMACR = 0x08,	/* DMA Control Register    */
-	ALI_FIFOCR1 = 0x0c,	/* FIFO Control Register 1  */
-	ALI_INTERFACECR = 0x10,	/* Interface Control Register */
-	ALI_INTERRUPTCR = 0x14,	/* Interrupt control Register */
-	ALI_INTERRUPTSR = 0x18,	/* Interrupt  Status Register */
-	ALI_FIFOCR2 = 0x1c,	/* FIFO Control Register 2   */
-	ALI_CPR = 0x20,		/* Command Port Register     */
-	ALI_SPR = 0x24,		/* Status Port Register      */
-	ALI_FIFOCR3 = 0x2c,	/* FIFO Control Register 3  */
-	ALI_TTSR = 0x30,	/* Transmit Tag Slot Register */
-	ALI_RTSR = 0x34,	/* Receive Tag Slot  Register */
-	ALI_CSPSR = 0x38,	/* Command/Status Port Status Register */
-	ALI_CAS = 0x3c,		/* Codec Write Semaphore Register */
-	ALI_SPDIFCSR = 0xf8,	/* spdif channel status register  */
-	ALI_SPDIFICS = 0xfc	/* spdif interface control/status  */
-};
-
-// x-status register(x:pcm in ,pcm out, mic in,)
-/* interrupts for a dma engine */
-#define DMA_INT_FIFO		(1<<4)	/* fifo under/over flow */
-#define DMA_INT_COMPLETE	(1<<3)	/* buffer read/write complete and ioc set */
-#define DMA_INT_LVI		(1<<2)	/* last valid done */
-#define DMA_INT_CELV		(1<<1)	/* last valid is current */
-#define DMA_INT_DCH		(1)	/* DMA Controller Halted (happens on LVI interrupts) */	//not eqult intel
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */// by interrupt status register finish
-
-#define INT_SPDIFOUT   (1<<23)	/* controller spdif out INTERRUPT */
-#define INT_SPDIFIN   (1<<22)
-#define INT_CODECSPDIFOUT   (1<<19)
-#define INT_MICIN   (1<<18)
-#define INT_PCMOUT   (1<<17)
-#define INT_PCMIN   (1<<16)
-#define INT_CPRAIS   (1<<7)
-#define INT_SPRAIS   (1<<5)
-#define INT_GPIO    (1<<1)
-#define INT_MASK   (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
-
-#define DRIVER_VERSION "0.02ac"
-
-/* magic numbers to protect our data structures */
-#define ALI5455_CARD_MAGIC		0x5072696E	/* "Prin" */
-#define ALI5455_STATE_MAGIC		0x63657373	/* "cess" */
-#define ALI5455_DMA_MASK		0xffffffff	/* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH			5	//I think 5 channel
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97		2
-
-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
-/* stream at a minimum for this card to be happy */
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
-/* values are one less than might be expected */
-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
-
-#define ALI5455
-static char *card_names[] = {
-	"ALI 5455"
-};
-
-static struct pci_device_id ali_pci_tbl[] = {
-	{PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
-	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
-	{0,}
-};
-
-MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
-
-#ifdef CONFIG_PM
-#define PM_SUSPENDED(card) (card->pm_suspended)
-#else
-#define PM_SUSPENDED(card) (0)
-#endif
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct ali_state {
-	unsigned int magic;
-	struct ali_card *card;	/* Card info */
-
-	/* single open lock mechanism, only used for recording */
-	struct mutex open_mutex;
-	wait_queue_head_t open_wait;
-
-	/* file mode */
-	mode_t open_mode;
-
-	/* virtual channel number */
-	int virt;
-
-#ifdef CONFIG_PM
-	unsigned int pm_saved_dac_rate, pm_saved_adc_rate;
-#endif
-	struct dmabuf {
-		/* wave sample stuff */
-		unsigned int rate;
-		unsigned char fmt, enable, trigger;
-
-		/* hardware channel */
-		struct ali_channel *read_channel;
-		struct ali_channel *write_channel;
-		struct ali_channel *codec_spdifout_channel;
-		struct ali_channel *controller_spdifout_channel;
-
-		/* OSS buffer management stuff */
-		void *rawbuf;
-		dma_addr_t dma_handle;
-		unsigned buforder;
-		unsigned numfrag;
-		unsigned fragshift;
-
-		/* our buffer acts like a circular ring */
-		unsigned hwptr;	/* where dma last started, updated by update_ptr */
-		unsigned swptr;	/* where driver last clear/filled, updated by read/write */
-		int count;	/* bytes to be consumed or been generated by dma machine */
-		unsigned total_bytes;	/* total bytes dmaed by hardware */
-
-		unsigned error;	/* number of over/underruns */
-		wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
-
-		/* redundant, but makes calculations easier */
-		/* what the hardware uses */
-		unsigned dmasize;
-		unsigned fragsize;
-		unsigned fragsamples;
-
-		/* what we tell the user to expect */
-		unsigned userfrags;
-		unsigned userfragsize;
-
-		/* OSS stuff */
-		unsigned mapped:1;
-		unsigned ready:1;
-		unsigned update_flag;
-		unsigned ossfragsize;
-		unsigned ossmaxfrags;
-		unsigned subdivision;
-	} dmabuf;
-};
-
-
-struct ali_card {
-	struct ali_channel channel[5];
-	unsigned int magic;
-
-	/* We keep ali5455 cards in a linked list */
-	struct ali_card *next;
-
-	/* The ali has a certain amount of cross channel interaction
-	   so we use a single per card lock */
-	spinlock_t lock;
-	spinlock_t ac97_lock;
-
-	/* PCI device stuff */
-	struct pci_dev *pci_dev;
-	u16 pci_id;
-#ifdef CONFIG_PM
-	u16 pm_suspended;
-	int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
-#endif
-	/* soundcore stuff */
-	int dev_audio;
-
-	/* structures for abstraction of hardware facilities, codecs, banks and channels */
-	struct ac97_codec *ac97_codec[NR_AC97];
-	struct ali_state *states[NR_HW_CH];
-
-	u16 ac97_features;
-	u16 ac97_status;
-	u16 channels;
-
-	/* hardware resources */
-	unsigned long iobase;
-
-	u32 irq;
-
-	/* Function support */
-	struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);
-	struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);
-	struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);
-	struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);
-	struct ali_channel *(*alloc_controller_spdifout_channel) (struct  ali_card *);
-	void (*free_pcm_channel) (struct ali_card *, int chan);
-
-	/* We have a *very* long init time possibly, so use this to block */
-	/* attempts to open our devices before we are ready (stops oops'es) */
-	int initializing;
-};
-
-
-static struct ali_card *devs = NULL;
-
-static int ali_open_mixdev(struct inode *inode, struct file *file);
-static int ali_ioctl_mixdev(struct inode *inode, struct file *file,
-			    unsigned int cmd, unsigned long arg);
-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);
-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card)
-{
-	if (card->channel[1].used == 1)
-		return NULL;
-	card->channel[1].used = 1;
-	return &card->channel[1];
-}
-
-static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card)
-{
-	if (card->channel[0].used == 1)
-		return NULL;
-	card->channel[0].used = 1;
-	return &card->channel[0];
-}
-
-static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card)
-{
-	if (card->channel[2].used == 1)
-		return NULL;
-	card->channel[2].used = 1;
-	return &card->channel[2];
-}
-
-static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card)
-{
-	if (card->channel[3].used == 1)
-		return NULL;
-	card->channel[3].used = 1;
-	return &card->channel[3];
-}
-
-static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card)
-{
-	if (card->channel[4].used == 1)
-		return NULL;
-	card->channel[4].used = 1;
-	return &card->channel[4];
-}
-static void ali_free_pcm_channel(struct ali_card *card, int channel)
-{
-	card->channel[channel].used = 0;
-}
-
-
-//add support  codec spdif out 
-static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
-{
-	unsigned long id = 0L;
-
-	id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);
-	id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
-	switch (id) {
-	case 0x41445361:	/* AD1886 */
-		if (rate == 48000) {
-			return 1;
-		}
-		break;
-	case 0x414c4720:	/* ALC650 */
-		if (rate == 48000) {
-			return 1;
-		}
-		break;
-	default:		/* all other codecs, until we know otherwiae */
-		if (rate == 48000 || rate == 44100 || rate == 32000) {
-			return 1;
-		}
-		break;
-	}
-	return (0);
-}
-
-/* ali_set_spdif_output
- * 
- *  Configure the S/PDIF output transmitter. When we turn on
- *  S/PDIF, we turn off the analog output. This may not be
- *  the right thing to do.
- *
- *  Assumptions:
- *     The DSP sample rate must already be set to a supported
- *     S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
- */
-static void ali_set_spdif_output(struct ali_state *state, int slots,
-				 int rate)
-{
-	int vol;
-	int aud_reg;
-	struct ac97_codec *codec = state->card->ac97_codec[0];
-
-	if (!(state->card->ac97_features & 4)) {
-		state->card->ac97_status &= ~SPDIF_ON;
-	} else {
-		if (slots == -1) {	/* Turn off S/PDIF */
-			aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
-			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-
-			/* If the volume wasn't muted before we turned on S/PDIF, unmute it */
-			if (!(state->card->ac97_status & VOL_MUTED)) {
-				aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-				ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
-					     (aud_reg & ~VOL_MUTED));
-			}
-			state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
-			return;
-		}
-
-		vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
-		state->card->ac97_status = vol & VOL_MUTED;
-
-		/* Set S/PDIF transmitter sample rate */
-		aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
-		switch (rate) {
-		case 32000:
-			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
-			break;
-		case 44100:
-			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
-			break;
-		case 48000:
-			aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
-			break;
-		default:
-			/* turn off S/PDIF */
-			aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
-			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-			state->card->ac97_status &= ~SPDIF_ON;
-			return;
-		}
-
-		ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
-
-		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
-		aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
-		ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-		aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
-		aud_reg |= 0x0002;
-		ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg);
-		udelay(1);
-
-		state->card->ac97_status |= SPDIF_ON;
-
-		/* Check to make sure the configuration is valid */
-		aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
-		if (!(aud_reg & 0x0400)) {
-			/* turn off S/PDIF */
-			ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-			state->card->ac97_status &= ~SPDIF_ON;
-			return;
-		}
-		if (codec_independent_spdif_locked > 0) {
-			aud_reg = ali_ac97_get(codec, 0x6a);
-			ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
-		}
-		/* Mute the analog output */
-		/* Should this only mute the PCM volume??? */
-	}
-}
-
-/* ali_set_dac_channels
- *
- *  Configure the codec's multi-channel DACs
- *
- *  The logic is backwards. Setting the bit to 1 turns off the DAC. 
- *
- *  What about the ICH? We currently configure it using the
- *  SNDCTL_DSP_CHANNELS ioctl.  If we're turnning on the DAC, 
- *  does that imply that we want the ICH set to support
- *  these channels?
- *  
- *  TODO:
- *    vailidate that the codec really supports these DACs
- *    before turning them on. 
- */
-static void ali_set_dac_channels(struct ali_state *state, int channel)
-{
-	int aud_reg;
-	struct ac97_codec *codec = state->card->ac97_codec[0];
-
-	aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
-	aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
-	state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
-
-	switch (channel) {
-	case 2:		/* always enabled */
-		break;
-	case 4:
-		aud_reg &= ~AC97_EA_PRJ;
-		state->card->ac97_status |= SURR_ON;
-		break;
-	case 6:
-		aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
-		state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
-		break;
-	default:
-		break;
-	}
-	ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-/* set playback sample rate */
-static unsigned int ali_set_dac_rate(struct ali_state *state,
-				     unsigned int rate)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	u32 new_rate;
-	struct ac97_codec *codec = state->card->ac97_codec[0];
-
-	if (!(state->card->ac97_features & 0x0001)) {
-		dmabuf->rate = clocking;
-		return clocking;
-	}
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 8000)
-		rate = 8000;
-	dmabuf->rate = rate;
-
-	/*
-	 *      Adjust for misclocked crap
-	 */
-
-	rate = (rate * clocking) / 48000;
-
-	if (strict_clocking && rate < 8000) {
-		rate = 8000;
-		dmabuf->rate = (rate * 48000) / clocking;
-	}
-
-	new_rate = ac97_set_dac_rate(codec, rate);
-	if (new_rate != rate) {
-		dmabuf->rate = (new_rate * 48000) / clocking;
-	}
-	rate = new_rate;
-	return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int ali_set_adc_rate(struct ali_state *state,
-				     unsigned int rate)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	u32 new_rate;
-	struct ac97_codec *codec = state->card->ac97_codec[0];
-
-	if (!(state->card->ac97_features & 0x0001)) {
-		dmabuf->rate = clocking;
-		return clocking;
-	}
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 8000)
-		rate = 8000;
-	dmabuf->rate = rate;
-
-	/*
-	 *      Adjust for misclocked crap
-	 */
-
-	rate = (rate * clocking) / 48000;
-	if (strict_clocking && rate < 8000) {
-		rate = 8000;
-		dmabuf->rate = (rate * 48000) / clocking;
-	}
-
-	new_rate = ac97_set_adc_rate(codec, rate);
-
-	if (new_rate != rate) {
-		dmabuf->rate = (new_rate * 48000) / clocking;
-		rate = new_rate;
-	}
-	return dmabuf->rate;
-}
-
-/* set codec independent spdifout sample rate */
-static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
-					       unsigned int rate)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-
-	if (!(state->card->ac97_features & 0x0001)) {
-		dmabuf->rate = clocking;
-		return clocking;
-	}
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 8000)
-		rate = 8000;
-	dmabuf->rate = rate;
-
-	return dmabuf->rate;
-}
-
-/* set  controller independent spdif out function sample rate */
-static void ali_set_spdifout_rate(struct ali_state *state,
-				  unsigned int rate)
-{
-	unsigned char ch_st_sel;
-	unsigned short status_rate;
-
-	switch (rate) {
-	case 44100:
-		status_rate = 0;
-		break;
-	case 32000:
-		status_rate = 0x300;
-		break;
-	case 48000:
-	default:
-		status_rate = 0x200;
-		break;
-	}
-
-	ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS;	//select spdif_out
-
-	ch_st_sel |= 0x80;	//select right
-	outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
-	outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2));
-
-	ch_st_sel &= (~0x80);	//select left
-	outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
-	outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
-   called with spinlock held! */
-
-static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned int civ, offset, port, port_picb;
-	unsigned int data;
-
-	if (!dmabuf->enable)
-		return 0;
-
-	if (rec == 1)
-		port = state->card->iobase + dmabuf->read_channel->port;
-	else if (rec == 2)
-		port = state->card->iobase + dmabuf->codec_spdifout_channel->port;
-	else if (rec == 3)
-		port = state->card->iobase + dmabuf->controller_spdifout_channel->port;
-	else
-		port = state->card->iobase + dmabuf->write_channel->port;
-
-	port_picb = port + OFF_PICB;
-
-	do {
-		civ = inb(port + OFF_CIV) & 31;
-		offset = inw(port_picb);
-		/* Must have a delay here! */
-		if (offset == 0)
-			udelay(1);
-
-		/* Reread both registers and make sure that that total
-		 * offset from the first reading to the second is 0.
-		 * There is an issue with SiS hardware where it will count
-		 * picb down to 0, then update civ to the next value,
-		 * then set the new picb to fragsize bytes.  We can catch
-		 * it between the civ update and the picb update, making
-		 * it look as though we are 1 fragsize ahead of where we
-		 * are.  The next to we get the address though, it will
-		 * be back in thdelay is more than long enough
-		 * that we won't have to worry about the chip still being
-		 * out of sync with reality ;-)
-		 */
-	} while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb));
-
-	data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
-	if (inw(port_picb) == 0)
-		data -= 2048;
-
-	return data;
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	struct ali_card *card = state->card;
-
-	dmabuf->enable &= ~ADC_RUNNING;
-
-	outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR);
-	udelay(1);
-
-	outb(0, card->iobase + PI_CR);
-	while (inb(card->iobase + PI_CR) != 0);
-
-	// now clear any latent interrupt bits (like the halt bit)
-	outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR);
-	outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_adc(struct ali_state *state)
-{
-	struct ali_card *card = state->card;
-	unsigned long flags;
-	spin_lock_irqsave(&card->lock, flags);
-	__stop_adc(state);
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_adc(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-
-	if (dmabuf->count < dmabuf->dmasize && dmabuf->ready
-	    && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-		dmabuf->enable |= ADC_RUNNING;
-		outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
-		if (state->card->channel[0].used == 1)
-			outl(1, state->card->iobase + ALI_DMACR);	// DMA CONTROL REGISTRER
-		udelay(100);
-		if (state->card->channel[2].used == 1)
-			outl((1 << 2), state->card->iobase + ALI_DMACR);	//DMA CONTROL REGISTER
-		udelay(100);
-	}
-}
-
-static void start_adc(struct ali_state *state)
-{
-	struct ali_card *card = state->card;
-	unsigned long flags;
-
-	spin_lock_irqsave(&card->lock, flags);
-	__start_adc(state);
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	struct ali_card *card = state->card;
-
-	dmabuf->enable &= ~DAC_RUNNING;
-	outl(0x00020000, card->iobase + 0x08);
-	outb(0, card->iobase + PO_CR);
-	while (inb(card->iobase + PO_CR) != 0)
-		cpu_relax();
-
-	outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR);
-
-	outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_dac(struct ali_state *state)
-{
-	struct ali_card *card = state->card;
-	unsigned long flags;
-	spin_lock_irqsave(&card->lock, flags);
-	__stop_dac(state);
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_dac(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
-	    (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-		dmabuf->enable |= DAC_RUNNING;
-		outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR);
-		outl((1 << 1), state->card->iobase + 0x08);	//dma control register
-	}
-}
-
-static void start_dac(struct ali_state *state)
-{
-	struct ali_card *card = state->card;
-	unsigned long flags;
-	spin_lock_irqsave(&card->lock, flags);
-	__start_dac(state);
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop codec and controller spdif out  (lock held) */
-static inline void __stop_spdifout(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	struct ali_card *card = state->card;
-
-	if (codec_independent_spdif_locked > 0) {
-		dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING;
-		outl((1 << 19), card->iobase + 0x08);
-		outb(0, card->iobase + CODECSPDIFOUT_CR);
-
-		while (inb(card->iobase + CODECSPDIFOUT_CR) != 0)
-			cpu_relax();
-
-		outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR);
-		outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR);
-	} else {
-		if (controller_independent_spdif_locked > 0) {
-			dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING;
-			outl((1 << 23), card->iobase + 0x08);
-			outb(0, card->iobase + CONTROLLERSPDIFOUT_CR);
-			while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0)
-				cpu_relax();
-			outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR);
-			outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR);
-		}
-	}
-}
-
-static void stop_spdifout(struct ali_state *state)
-{
-	struct ali_card *card = state->card;
-	unsigned long flags;
-	spin_lock_irqsave(&card->lock, flags);
-	__stop_spdifout(state);
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_spdifout(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
-	    (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
-		if (codec_independent_spdif_locked > 0) {
-			dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;
-			outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);
-			outl((1 << 3), state->card->iobase + 0x08);	//dma control register
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;
-				outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);
-				outl((1 << 7), state->card->iobase + 0x08);	//dma control register
-			}
-		}
-	}
-}
-
-static void start_spdifout(struct ali_state *state)
-{
-	struct ali_card *card = state->card;
-	unsigned long flags;
-	spin_lock_irqsave(&card->lock, flags);
-	__start_spdifout(state);
-	spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback , recording,spdif out  buffer should be allocated separately */
-static int alloc_dmabuf(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	void *rawbuf = NULL;
-	int order, size;
-	struct page *page, *pend;
-
-	/* If we don't have any oss frag params, then use our default ones */
-	if (dmabuf->ossmaxfrags == 0)
-		dmabuf->ossmaxfrags = 4;
-	if (dmabuf->ossfragsize == 0)
-		dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags;
-	size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-
-	if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
-		return 0;
-	/* alloc enough to satisfy the oss params */
-	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
-		if ((PAGE_SIZE << order) > size)
-			continue;
-		if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
-						   PAGE_SIZE << order,
-						   &dmabuf->dma_handle)))
-			break;
-	}
-	if (!rawbuf)
-		return -ENOMEM;
-
-	dmabuf->ready = dmabuf->mapped = 0;
-	dmabuf->rawbuf = rawbuf;
-	dmabuf->buforder = order;
-
-	/* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
-	for (page = virt_to_page(rawbuf); page <= pend; page++)
-		SetPageReserved(page);
-	return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	struct page *page, *pend;
-
-	if (dmabuf->rawbuf) {
-		/* undo marking the pages as reserved */
-		pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
-		for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
-			ClearPageReserved(page);
-		pci_free_consistent(state->card->pci_dev,
-				    PAGE_SIZE << dmabuf->buforder,
-				    dmabuf->rawbuf, dmabuf->dma_handle);
-	}
-	dmabuf->rawbuf = NULL;
-	dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct ali_state *state, unsigned rec)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	struct ali_channel *c = NULL;
-	struct sg_item *sg;
-	unsigned long flags;
-	int ret;
-	unsigned fragint;
-	int i;
-
-	spin_lock_irqsave(&state->card->lock, flags);
-	if (dmabuf->enable & DAC_RUNNING)
-		__stop_dac(state);
-	if (dmabuf->enable & ADC_RUNNING)
-		__stop_adc(state);
-	if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
-		__stop_spdifout(state);
-	if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-		__stop_spdifout(state);
-
-	dmabuf->total_bytes = 0;
-	dmabuf->count = dmabuf->error = 0;
-	dmabuf->swptr = dmabuf->hwptr = 0;
-	spin_unlock_irqrestore(&state->card->lock, flags);
-
-	/* allocate DMA buffer, let alloc_dmabuf determine if we are already
-	 * allocated well enough or if we should replace the current buffer
-	 * (assuming one is already allocated, if it isn't, then allocate it).
-	 */
-	if ((ret = alloc_dmabuf(state)))
-		return ret;
-
-	/* FIXME: figure out all this OSS fragment stuff */
-	/* I did, it now does what it should according to the OSS API.  DL */
-	/* We may not have realloced our dmabuf, but the fragment size to
-	 * fragment number ratio may have changed, so go ahead and reprogram
-	 * things
-	 */
-
-	dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
-	dmabuf->numfrag = SG_LEN;
-	dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag;
-	dmabuf->fragsamples = dmabuf->fragsize >> 1;
-	dmabuf->userfragsize = dmabuf->ossfragsize;
-	dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;
-
-	memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
-	if (dmabuf->ossmaxfrags == 4) {
-		fragint = 8;
-		dmabuf->fragshift = 2;
-	} else if (dmabuf->ossmaxfrags == 8) {
-		fragint = 4;
-		dmabuf->fragshift = 3;
-	} else if (dmabuf->ossmaxfrags == 16) {
-		fragint = 2;
-		dmabuf->fragshift = 4;
-	} else {
-		fragint = 1;
-		dmabuf->fragshift = 5;
-	}
-	/*
-	 *      Now set up the ring 
-	 */
-
-	if (rec == 1)
-		c = dmabuf->read_channel;
-	else if (rec == 2)
-		c = dmabuf->codec_spdifout_channel;
-	else if (rec == 3)
-		c = dmabuf->controller_spdifout_channel;
-	else if (rec == 0)
-		c = dmabuf->write_channel;
-	if (c != NULL) {
-		sg = &c->sg[0];
-		/*
-		 *      Load up 32 sg entries and take an interrupt at half
-		 *      way (we might want more interrupts later..) 
-		 */
-		for (i = 0; i < dmabuf->numfrag; i++) {
-			sg->busaddr =
-			    virt_to_bus(dmabuf->rawbuf +
-					dmabuf->fragsize * i);
-			// the card will always be doing 16bit stereo
-			sg->control = dmabuf->fragsamples;
-			sg->control |= CON_BUFPAD;	//I modify
-			// set us up to get IOC interrupts as often as needed to
-			// satisfy numfrag requirements, no more
-			if (((i + 1) % fragint) == 0) {
-				sg->control |= CON_IOC;
-			}
-			sg++;
-		}
-		spin_lock_irqsave(&state->card->lock, flags);
-		outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */
-		outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
-		outb(0, state->card->iobase + c->port + OFF_CIV);
-		outb(0, state->card->iobase + c->port + OFF_LVI);
-		spin_unlock_irqrestore(&state->card->lock, flags);
-	}
-	/* set the ready flag for the dma buffer */
-	dmabuf->ready = 1;
-	return 0;
-}
-
-static void __ali_update_lvi(struct ali_state *state, int rec)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	int x, port;
-	port = state->card->iobase;
-	if (rec == 1)
-		port += dmabuf->read_channel->port;
-	else if (rec == 2)
-		port += dmabuf->codec_spdifout_channel->port;
-	else if (rec == 3)
-		port += dmabuf->controller_spdifout_channel->port;
-	else if (rec == 0)
-		port += dmabuf->write_channel->port;
-	/* if we are currently stopped, then our CIV is actually set to our
-	 * *last* sg segment and we are ready to wrap to the next.  However,
-	 * if we set our LVI to the last sg segment, then it won't wrap to
-	 * the next sg segment, it won't even get a start.  So, instead, when
-	 * we are stopped, we set both the LVI value and also we increment
-	 * the CIV value to the next sg segment to be played so that when
-	 * we call start_{dac,adc}, things will operate properly
-	 */
-	if (!dmabuf->enable && dmabuf->ready) {
-		if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
-			__start_adc(state);
-			while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
-				cpu_relax();
-		} else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-			outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
-			__start_dac(state);
-			while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
-				cpu_relax();
-		} else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
-			if (codec_independent_spdif_locked > 0) {
-				// outb((inb(port+OFF_CIV))&31, port+OFF_LVI);
-				outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
-				__start_spdifout(state);
-				while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
-					cpu_relax();
-			} else {
-				if (controller_independent_spdif_locked > 0) {
-					outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
-					__start_spdifout(state);
-					while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
-						cpu_relax();
-				}
-			}
-		}
-	}
-
-	/* swptr - 1 is the tail of our transfer */
-	x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
-	x /= dmabuf->fragsize;
-	outb(x, port + OFF_LVI);
-}
-
-static void ali_update_lvi(struct ali_state *state, int rec)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned long flags;
-	if (!dmabuf->ready)
-		return;
-	spin_lock_irqsave(&state->card->lock, flags);
-	__ali_update_lvi(state, rec);
-	spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void ali_update_ptr(struct ali_state *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned hwptr;
-	int diff;
-	
-	/* error handling and process wake up for DAC */
-	if (dmabuf->enable == ADC_RUNNING) {
-		/* update hardware pointer */
-		hwptr = ali_get_dma_addr(state, 1);
-		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-		dmabuf->hwptr = hwptr;
-		dmabuf->total_bytes += diff;
-		dmabuf->count += diff;
-		if (dmabuf->count > dmabuf->dmasize) {
-			/* buffer underrun or buffer overrun */
-			/* this is normal for the end of a read */
-			/* only give an error if we went past the */
-			/* last valid sg entry */
-			if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) {
-				printk(KERN_WARNING "ali_audio: DMA overrun on read\n");
-				dmabuf->error++;
-			}
-		}
-		if (dmabuf->count > dmabuf->userfragsize)
-			wake_up(&dmabuf->wait);
-	}
-	/* error handling and process wake up for DAC */
-	if (dmabuf->enable == DAC_RUNNING) {
-		/* update hardware pointer */
-		hwptr = ali_get_dma_addr(state, 0);
-		diff =
-		    (dmabuf->dmasize + hwptr -
-		     dmabuf->hwptr) % dmabuf->dmasize;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
-		printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
-		dmabuf->hwptr = hwptr;
-		dmabuf->total_bytes += diff;
-		dmabuf->count -= diff;
-		if (dmabuf->count < 0) {
-			/* buffer underrun or buffer overrun */
-			/* this is normal for the end of a write */
-			/* only give an error if we went past the */
-			/* last valid sg entry */
-			if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) {
-				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
-				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
-				     			inb(state->card->iobase + PO_CIV) & 31,
-				     			inb(state->card->iobase + PO_LVI) & 31, 
-							dmabuf->hwptr,
-							dmabuf->count);
-				dmabuf->error++;
-			}
-		}
-		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
-		    	wake_up(&dmabuf->wait);
-	}
-
-	/* error handling and process wake up for CODEC SPDIF OUT */
-	if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
-		/* update hardware pointer */
-		hwptr = ali_get_dma_addr(state, 2);
-		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-		dmabuf->hwptr = hwptr;
-		dmabuf->total_bytes += diff;
-		dmabuf->count -= diff;
-		if (dmabuf->count < 0) {
-			/* buffer underrun or buffer overrun */
-			/* this is normal for the end of a write */
-			/* only give an error if we went past the */
-			/* last valid sg entry */
-			if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) {
-				printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
-				printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n", 
-				        inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31,
-					inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31,
-					dmabuf->hwptr, dmabuf->count);
-				dmabuf->error++;
-			}
-		}
-		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
-			wake_up(&dmabuf->wait);
-	}
-	/* error handling and process wake up for CONTROLLER SPDIF OUT */
-	if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
-		/* update hardware pointer */
-		hwptr = ali_get_dma_addr(state, 3);
-		diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
-		dmabuf->hwptr = hwptr;
-		dmabuf->total_bytes += diff;
-		dmabuf->count -= diff;
-		if (dmabuf->count < 0) {
-			/* buffer underrun or buffer overrun */
-			/* this is normal for the end of a write */
-			/* only give an error if we went past the */
-			/* last valid sg entry */
-			if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) {
-				printk(KERN_WARNING
-				       "ali_audio: DMA overrun on write\n");
-				printk("ali_audio: CIV %d, LVI %d, hwptr %x, "
-					"count %d\n",
-				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31,
-				     		inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31,
-				     		dmabuf->hwptr, dmabuf->count);
-				dmabuf->error++;
-			}
-		}
-		if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
-			wake_up(&dmabuf->wait);
-	}
-}
-
-static inline int ali_get_free_write_space(struct
-					   ali_state
-					   *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	int free;
-
-	if (dmabuf->count < 0) {
-		dmabuf->count = 0;
-		dmabuf->swptr = dmabuf->hwptr;
-	}
-	free = dmabuf->dmasize - dmabuf->swptr;
-	if ((dmabuf->count + free) > dmabuf->dmasize){
-		free = dmabuf->dmasize - dmabuf->count;
-	}
-	return free;
-}
-
-static inline int ali_get_available_read_data(struct
-					      ali_state
-					      *state)
-{
-	struct dmabuf *dmabuf = &state->dmabuf;
-	int avail;
-	ali_update_ptr(state);
-	// catch overruns during record
-	if (dmabuf->count > dmabuf->dmasize) {
-		dmabuf->count = dmabuf->dmasize;
-		dmabuf->swptr = dmabuf->hwptr;
-	}
-	avail = dmabuf->count;
-	avail -= (dmabuf->hwptr % dmabuf->fragsize);
-	if (avail < 0)
-		return (0);
-	return (avail);
-}
-
-static int drain_dac(struct ali_state *state, int signals_allowed)
-{
-
-	DECLARE_WAITQUEUE(wait, current);
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned long flags;
-	unsigned long tmo;
-	int count;
-	if (!dmabuf->ready)
-		return 0;
-	if (dmabuf->mapped) {
-		stop_dac(state);
-		return 0;
-	}
-	add_wait_queue(&dmabuf->wait, &wait);
-	for (;;) {
-
-		spin_lock_irqsave(&state->card->lock, flags);
-		ali_update_ptr(state);
-		count = dmabuf->count;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-		if (count <= 0)
-			break;
-		/* 
-		 * This will make sure that our LVI is correct, that our
-		 * pointer is updated, and that the DAC is running.  We
-		 * have to force the setting of dmabuf->trigger to avoid
-		 * any possible deadlocks.
-		 */
-		if (!dmabuf->enable) {
-			dmabuf->trigger = PCM_ENABLE_OUTPUT;
-			ali_update_lvi(state, 0);
-		}
-		if (signal_pending(current) && signals_allowed) {
-			break;
-		}
-
-		/* It seems that we have to set the current state to
-		 * TASK_INTERRUPTIBLE every time to make the process
-		 * really go to sleep.  This also has to be *after* the
-		 * update_ptr() call because update_ptr is likely to
-		 * do a wake_up() which will unset this before we ever
-		 * try to sleep, resuling in a tight loop in this code
-		 * instead of actually sleeping and waiting for an
-		 * interrupt to wake us up!
-		 */
-		set_current_state(TASK_INTERRUPTIBLE);
-		/*
-		 * set the timeout to significantly longer than it *should*
-		 * take for the DAC to drain the DMA buffer
-		 */
-		tmo = (count * HZ) / (dmabuf->rate);
-		if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-			printk(KERN_ERR "ali_audio: drain_dac, dma timeout?\n");
-			count = 0;
-			break;
-		}
-	}
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&dmabuf->wait, &wait);
-	if (count > 0 && signal_pending(current) && signals_allowed)
-		return -ERESTARTSYS;
-	stop_dac(state);
-	return 0;
-}
-
-
-static int drain_spdifout(struct ali_state *state, int signals_allowed)
-{
-
-	DECLARE_WAITQUEUE(wait, current);
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned long flags;
-	unsigned long tmo;
-	int count;
-	if (!dmabuf->ready)
-		return 0;
-	if (dmabuf->mapped) {
-		stop_spdifout(state);
-		return 0;
-	}
-	add_wait_queue(&dmabuf->wait, &wait);
-	for (;;) {
-
-		spin_lock_irqsave(&state->card->lock, flags);
-		ali_update_ptr(state);
-		count = dmabuf->count;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-		if (count <= 0)
-			break;
-		/* 
-		 * This will make sure that our LVI is correct, that our
-		 * pointer is updated, and that the DAC is running.  We
-		 * have to force the setting of dmabuf->trigger to avoid
-		 * any possible deadlocks.
-		 */
-		if (!dmabuf->enable) {
-			if (codec_independent_spdif_locked > 0) {
-				dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
-				ali_update_lvi(state, 2);
-			} else {
-				if (controller_independent_spdif_locked > 0) {
-					dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
-					ali_update_lvi(state, 3);
-				}
-			}
-		}
-		if (signal_pending(current) && signals_allowed) {
-			break;
-		}
-
-		/* It seems that we have to set the current state to
-		 * TASK_INTERRUPTIBLE every time to make the process
-		 * really go to sleep.  This also has to be *after* the
-		 * update_ptr() call because update_ptr is likely to
-		 * do a wake_up() which will unset this before we ever
-		 * try to sleep, resuling in a tight loop in this code
-		 * instead of actually sleeping and waiting for an
-		 * interrupt to wake us up!
-		 */
-		set_current_state(TASK_INTERRUPTIBLE);
-		/*
-		 * set the timeout to significantly longer than it *should*
-		 * take for the DAC to drain the DMA buffer
-		 */
-		tmo = (count * HZ) / (dmabuf->rate);
-		if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-			printk(KERN_ERR "ali_audio: drain_spdifout, dma timeout?\n");
-			count = 0;
-			break;
-		}
-	}
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&dmabuf->wait, &wait);
-	if (count > 0 && signal_pending(current) && signals_allowed)
-		return -ERESTARTSYS;
-	stop_spdifout(state);
-	return 0;
-}
-
-static void ali_channel_interrupt(struct ali_card *card)
-{
-	int i, count;
-	
-	for (i = 0; i < NR_HW_CH; i++) {
-		struct ali_state *state = card->states[i];
-		struct ali_channel *c = NULL;
-		struct dmabuf *dmabuf;
-		unsigned long port = card->iobase;
-		u16 status;
-		if (!state)
-			continue;
-		if (!state->dmabuf.ready)
-			continue;
-		dmabuf = &state->dmabuf;
-		if (codec_independent_spdif_locked > 0) {
-			if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
-				c = dmabuf->codec_spdifout_channel;
-			}
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-					c = dmabuf->controller_spdifout_channel;
-			} else {
-				if (dmabuf->enable & DAC_RUNNING) {
-					c = dmabuf->write_channel;
-				} else if (dmabuf->enable & ADC_RUNNING) {
-					c = dmabuf->read_channel;
-				} else
-					continue;
-			}
-		}
-		port += c->port;
-
-		status = inw(port + OFF_SR);
-
-		if (status & DMA_INT_COMPLETE) {
-			/* only wake_up() waiters if this interrupt signals
-			 * us being beyond a userfragsize of data open or
-			 * available, and ali_update_ptr() does that for
-			 * us
-			 */
-			ali_update_ptr(state);
-		}
-
-		if (status & DMA_INT_LVI) {
-			ali_update_ptr(state);
-			wake_up(&dmabuf->wait);
-
-			if (dmabuf->enable & DAC_RUNNING)
-				count = dmabuf->count;
-			else if (dmabuf->enable & ADC_RUNNING)
-				count = dmabuf->dmasize - dmabuf->count;
-			else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
-				count = dmabuf->count;
-			else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-				count = dmabuf->count;
-			else count = 0;
-
-			if (count > 0) {
-				if (dmabuf->enable & DAC_RUNNING)
-					outl((1 << 1), state->card->iobase + ALI_DMACR);
-				else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
-						outl((1 << 3), state->card->iobase + ALI_DMACR);
-				else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-					outl((1 << 7), state->card->iobase + ALI_DMACR);
-			} else {
-				if (dmabuf->enable & DAC_RUNNING)
-					__stop_dac(state);
-				if (dmabuf->enable & ADC_RUNNING)
-					__stop_adc(state);
-				if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
-					__stop_spdifout(state);
-				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-					__stop_spdifout(state);
-				dmabuf->enable = 0;
-				wake_up(&dmabuf->wait);
-			}
-
-		}
-		if (!(status & DMA_INT_DCH)) {
-			ali_update_ptr(state);
-			wake_up(&dmabuf->wait);
-			if (dmabuf->enable & DAC_RUNNING)
-				count = dmabuf->count;
-			else if (dmabuf->enable & ADC_RUNNING)
-				count = dmabuf->dmasize - dmabuf->count;
-			else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
-				count = dmabuf->count;
-			else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-				count = dmabuf->count;
-			else
-				count = 0;
-
-			if (count > 0) {
-				if (dmabuf->enable & DAC_RUNNING)
-					outl((1 << 1), state->card->iobase + ALI_DMACR);
-				else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
-					outl((1 << 3), state->card->iobase + ALI_DMACR);
-				else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-					outl((1 << 7), state->card->iobase + ALI_DMACR);
-			} else {
-				if (dmabuf->enable & DAC_RUNNING)
-					__stop_dac(state);
-				if (dmabuf->enable & ADC_RUNNING)
-					__stop_adc(state);
-				if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
-					__stop_spdifout(state);
-				if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
-					__stop_spdifout(state);
-				dmabuf->enable = 0;
-				wake_up(&dmabuf->wait);
-			}
-		}
-		outw(status & DMA_INT_MASK, port + OFF_SR);
-	}
-}
-
-static irqreturn_t ali_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct ali_card *card = (struct ali_card *) dev_id;
-	u32 status;
-	u16 status2;
-
-	spin_lock(&card->lock);
-	status = inl(card->iobase + ALI_INTERRUPTSR);
-	if (!(status & INT_MASK)) {
-		spin_unlock(&card->lock);
-		return IRQ_NONE;		/* not for us */
-	}
-
-	if (codec_independent_spdif_locked > 0) {
-		if (globel == 0) {
-			globel += 1;
-			status2 = inw(card->iobase + 0x76);
-			outw(status2 | 0x000c, card->iobase + 0x76);
-		} else {
-			if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
-				ali_channel_interrupt(card);
-		}
-	} else {
-		if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
-			ali_channel_interrupt(card);
-	}
-
-	/* clear 'em */
-	outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
-	spin_unlock(&card->lock);
-	return IRQ_HANDLED;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is
-   waiting to be copied to the user's buffer.  It is filled by the dma
-   machine and drained by this loop. */
-
-static ssize_t ali_read(struct file *file, char __user *buffer,
-			size_t count, loff_t * ppos)
-{
-	struct ali_state *state = (struct ali_state *) file->private_data;
-	struct ali_card *card = state ? state->card : NULL;
-	struct dmabuf *dmabuf = &state->dmabuf;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned int swptr;
-	int cnt;
-	DECLARE_WAITQUEUE(waita, current);
-#ifdef DEBUG2
-	printk("ali_audio: ali_read called, count = %d\n", count);
-#endif
-	if (dmabuf->mapped)
-		return -ENXIO;
-	if (dmabuf->enable & DAC_RUNNING)
-		return -ENODEV;
-	if (!dmabuf->read_channel) {
-		dmabuf->ready = 0;
-		dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
-		if (!dmabuf->read_channel) {
-			return -EBUSY;
-		}
-	}
-	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-	add_wait_queue(&dmabuf->wait, &waita);
-	while (count > 0) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irqsave(&card->lock, flags);
-		if (PM_SUSPENDED(card)) {
-			spin_unlock_irqrestore(&card->lock, flags);
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			continue;
-		}
-		swptr = dmabuf->swptr;
-		cnt = ali_get_available_read_data(state);
-		// this is to make the copy_to_user simpler below
-		if (cnt > (dmabuf->dmasize - swptr))
-			cnt = dmabuf->dmasize - swptr;
-		spin_unlock_irqrestore(&card->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		/* Lop off the last two bits to force the code to always
-		 * write in full samples.  This keeps software that sets
-		 * O_NONBLOCK but doesn't check the return value of the
-		 * write call from getting things out of state where they
-		 * think a full 4 byte sample was written when really only
-		 * a portion was, resulting in odd sound and stereo
-		 * hysteresis.
-		 */
-		cnt &= ~0x3;
-		if (cnt <= 0) {
-			unsigned long tmo;
-			/*
-			 * Don't let us deadlock.  The ADC won't start if
-			 * dmabuf->trigger isn't set.  A call to SETTRIGGER
-			 * could have turned it off after we set it to on
-			 * previously.
-			 */
-			dmabuf->trigger = PCM_ENABLE_INPUT;
-			/*
-			 * This does three things.  Updates LVI to be correct,
-			 * makes sure the ADC is running, and updates the
-			 * hwptr.
-			 */
-			ali_update_lvi(state, 1);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				goto done;
-			}
-			/* Set the timeout to how long it would take to fill
-			 * two of our buffers.  If we haven't been woke up
-			 * by then, then we know something is wrong.
-			 */
-			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
-			    
-			/* There are two situations when sleep_on_timeout returns, one is when
-			   the interrupt is serviced correctly and the process is waked up by
-			   ISR ON TIME. Another is when timeout is expired, which means that
-			   either interrupt is NOT serviced correctly (pending interrupt) or it
-			   is TOO LATE for the process to be scheduled to run (scheduler latency)
-			   which results in a (potential) buffer overrun. And worse, there is
-			   NOTHING we can do to prevent it. */
-			if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
-				printk(KERN_ERR
-				       "ali_audio: recording schedule timeout, "
-				       "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       dmabuf->dmasize, dmabuf->fragsize,
-				       dmabuf->count, dmabuf->hwptr,
-				       dmabuf->swptr);
-				/* a buffer overrun, we delay the recovery until next time the
-				   while loop begin and we REALLY have space to record */
-			}
-			if (signal_pending(current)) {
-				ret = ret ? ret : -ERESTARTSYS;
-				goto done;
-			}
-			continue;
-		}
-
-		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			goto done;
-		}
-
-		swptr = (swptr + cnt) % dmabuf->dmasize;
-		spin_lock_irqsave(&card->lock, flags);
-		if (PM_SUSPENDED(card)) {
-			spin_unlock_irqrestore(&card->lock, flags);
-			continue;
-		}
-		dmabuf->swptr = swptr;
-		dmabuf->count -= cnt;
-		spin_unlock_irqrestore(&card->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-	}
-done:
-	ali_update_lvi(state, 1);
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&dmabuf->wait, &waita);
-	return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
-   the soundcard.  it is drained by the dma machine and filled by this loop. */
-static ssize_t ali_write(struct file *file,
-			 const char __user *buffer, size_t count, loff_t * ppos)
-{
-	struct ali_state *state = (struct ali_state *) file->private_data;
-	struct ali_card *card = state ? state->card : NULL;
-	struct dmabuf *dmabuf = &state->dmabuf;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned int swptr = 0;
-	int cnt, x;
-	DECLARE_WAITQUEUE(waita, current);
-#ifdef DEBUG2
-	printk("ali_audio: ali_write called, count = %d\n", count);
-#endif
-	if (dmabuf->mapped)
-		return -ENXIO;
-	if (dmabuf->enable & ADC_RUNNING)
-		return -ENODEV;
-	if (codec_independent_spdif_locked > 0) {
-		if (!dmabuf->codec_spdifout_channel) {
-			dmabuf->ready = 0;
-			dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card);
-			if (!dmabuf->codec_spdifout_channel)
-				return -EBUSY;
-		}
-	} else {
-		if (controller_independent_spdif_locked > 0) {
-			if (!dmabuf->controller_spdifout_channel) {
-				dmabuf->ready = 0;
-				dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card);
-				if (!dmabuf->controller_spdifout_channel)
-					return -EBUSY;
-			}
-		} else {
-			if (!dmabuf->write_channel) {
-				dmabuf->ready = 0;
-				dmabuf->write_channel =
-				    card->alloc_pcm_channel(card);
-				if (!dmabuf->write_channel)
-					return -EBUSY;
-			}
-		}
-	}
-
-	if (codec_independent_spdif_locked > 0) {
-		if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
-			return ret;
-	} else {
-		if (controller_independent_spdif_locked > 0) {
-			if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
-				return ret;
-		} else {
-
-			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-				return ret;
-		}
-	}
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	ret = 0;
-	add_wait_queue(&dmabuf->wait, &waita);
-	while (count > 0) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irqsave(&state->card->lock, flags);
-		if (PM_SUSPENDED(card)) {
-			spin_unlock_irqrestore(&card->lock, flags);
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			continue;
-		}
-
-		swptr = dmabuf->swptr;
-		cnt = ali_get_free_write_space(state);
-		/* Bound the maximum size to how much we can copy to the
-		 * dma buffer before we hit the end.  If we have more to
-		 * copy then it will get done in a second pass of this
-		 * loop starting from the beginning of the buffer.
-		 */
-		if (cnt > (dmabuf->dmasize - swptr))
-			cnt = dmabuf->dmasize - swptr;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG2
-		printk(KERN_INFO
-		       "ali_audio: ali_write: %d bytes available space\n",
-		       cnt);
-#endif
-		if (cnt > count)
-			cnt = count;
-		/* Lop off the last two bits to force the code to always
-		 * write in full samples.  This keeps software that sets
-		 * O_NONBLOCK but doesn't check the return value of the
-		 * write call from getting things out of state where they
-		 * think a full 4 byte sample was written when really only
-		 * a portion was, resulting in odd sound and stereo
-		 * hysteresis.
-		 */
-		cnt &= ~0x3;
-		if (cnt <= 0) {
-			unsigned long tmo;
-			// There is data waiting to be played
-			/*
-			 * Force the trigger setting since we would
-			 * deadlock with it set any other way
-			 */
-			if (codec_independent_spdif_locked > 0) {
-				dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
-				ali_update_lvi(state, 2);
-			} else {
-				if (controller_independent_spdif_locked > 0) {
-					dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
-					ali_update_lvi(state, 3);
-				} else {
-
-					dmabuf->trigger = PCM_ENABLE_OUTPUT;
-					ali_update_lvi(state, 0);
-				}
-			}
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				goto ret;
-			}
-			/* Not strictly correct but works */
-			tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
-			/* There are two situations when sleep_on_timeout returns, one is when
-			   the interrupt is serviced correctly and the process is waked up by
-			   ISR ON TIME. Another is when timeout is expired, which means that
-			   either interrupt is NOT serviced correctly (pending interrupt) or it
-			   is TOO LATE for the process to be scheduled to run (scheduler latency)
-			   which results in a (potential) buffer underrun. And worse, there is
-			   NOTHING we can do to prevent it. */
-			   
-			/* FIXME - do timeout handling here !! */
-			schedule_timeout(tmo >= 2 ? tmo : 2);
-
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				goto ret;
-			}
-			continue;
-		}
-		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			goto ret;
-		}
-
-		swptr = (swptr + cnt) % dmabuf->dmasize;
-		spin_lock_irqsave(&state->card->lock, flags);
-		if (PM_SUSPENDED(card)) {
-			spin_unlock_irqrestore(&card->lock, flags);
-			continue;
-		}
-
-		dmabuf->swptr = swptr;
-		dmabuf->count += cnt;
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-	}
-	if (swptr % dmabuf->fragsize) {
-		x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
-		memset(dmabuf->rawbuf + swptr, '\0', x);
-	}
-ret:
-	if (codec_independent_spdif_locked > 0) {
-		ali_update_lvi(state, 2);
-	} else {
-		if (controller_independent_spdif_locked > 0) {
-			ali_update_lvi(state, 3);
-		} else {
-			ali_update_lvi(state, 0);
-		}
-	}
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&dmabuf->wait, &waita);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int ali_poll(struct file *file, struct poll_table_struct
-			     *wait)
-{
-	struct ali_state *state = (struct ali_state *) file->private_data;
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned long flags;
-	unsigned int mask = 0;
-	if (!dmabuf->ready)
-		return 0;
-	poll_wait(file, &dmabuf->wait, wait);
-	spin_lock_irqsave(&state->card->lock, flags);
-	ali_update_ptr(state);
-	if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
-		if (dmabuf->count >= (signed) dmabuf->fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE  && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) {
-		if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize)
-			mask |= POLLOUT | POLLWRNORM;
-	}
-	spin_unlock_irqrestore(&state->card->lock, flags);
-	return mask;
-}
-
-static int ali_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct ali_state *state = (struct ali_state *) file->private_data;
-	struct dmabuf *dmabuf = &state->dmabuf;
-	int ret = -EINVAL;
-	unsigned long size;
-	lock_kernel();
-	if (vma->vm_flags & VM_WRITE) {
-		if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) {
-			ret = -EBUSY;
-			goto out;
-		}
-	}
-	if (vma->vm_flags & VM_READ) {
-		if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
-			ret = -EBUSY;
-			goto out;
-		}
-	}
-	if ((ret = prog_dmabuf(state, 0)) != 0)
-		goto out;
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << dmabuf->buforder))
-		goto out;
-	ret = -EAGAIN;
-	if (remap_pfn_range(vma, vma->vm_start,
-				virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
-				size, vma->vm_page_prot))
-		goto out;
-	dmabuf->mapped = 1;
-	dmabuf->trigger = 0;
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct ali_state *state = (struct ali_state *) file->private_data;
-	struct ali_channel *c = NULL;
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned long flags;
-	audio_buf_info abinfo;
-	count_info cinfo;
-	unsigned int i_scr;
-	int val = 0, ret;
-	struct ac97_codec *codec = state->card->ac97_codec[0];
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-#ifdef DEBUG
-	printk("ali_audio: ali_ioctl, arg=0x%x, cmd=",
-	       arg ? *p : 0);
-#endif
-	switch (cmd) {
-	case OSS_GETVERSION:
-#ifdef DEBUG
-		printk("OSS_GETVERSION\n");
-#endif
-		return put_user(SOUND_VERSION, p);
-	case SNDCTL_DSP_RESET:
-#ifdef DEBUG
-		printk("SNDCTL_DSP_RESET\n");
-#endif
-		spin_lock_irqsave(&state->card->lock, flags);
-		if (dmabuf->enable == DAC_RUNNING) {
-			c = dmabuf->write_channel;
-			__stop_dac(state);
-		}
-		if (dmabuf->enable == ADC_RUNNING) {
-			c = dmabuf->read_channel;
-			__stop_adc(state);
-		}
-		if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
-			c = dmabuf->codec_spdifout_channel;
-			__stop_spdifout(state);
-		}
-		if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
-			c = dmabuf->controller_spdifout_channel;
-			__stop_spdifout(state);
-		}
-		if (c != NULL) {
-			outb(2, state->card->iobase + c->port + OFF_CR);	/* reset DMA machine */
-			outl(virt_to_bus(&c->sg[0]),
-			     state->card->iobase + c->port + OFF_BDBAR);
-			outb(0, state->card->iobase + c->port + OFF_CIV);
-			outb(0, state->card->iobase + c->port + OFF_LVI);
-		}
-
-		spin_unlock_irqrestore(&state->card->lock, flags);
-		synchronize_irq(state->card->pci_dev->irq);
-		dmabuf->ready = 0;
-		dmabuf->swptr = dmabuf->hwptr = 0;
-		dmabuf->count = dmabuf->total_bytes = 0;
-		return 0;
-	case SNDCTL_DSP_SYNC:
-#ifdef DEBUG
-		printk("SNDCTL_DSP_SYNC\n");
-#endif
-		if (codec_independent_spdif_locked > 0) {
-			if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING
-			    || file->f_flags & O_NONBLOCK)
-				return 0;
-			if ((val = drain_spdifout(state, 1)))
-				return val;
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				if (dmabuf->enable !=
-				    CONTROLLER_SPDIFOUT_RUNNING
-				    || file->f_flags & O_NONBLOCK)
-					return 0;
-				if ((val = drain_spdifout(state, 1)))
-					return val;
-			} else {
-				if (dmabuf->enable != DAC_RUNNING
-				    || file->f_flags & O_NONBLOCK)
-					return 0;
-				if ((val = drain_dac(state, 1)))
-					return val;
-			}
-		}
-		dmabuf->total_bytes = 0;
-		return 0;
-	case SNDCTL_DSP_SPEED:	/* set smaple rate */
-#ifdef DEBUG
-		printk("SNDCTL_DSP_SPEED\n");
-#endif
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-			if (file->f_mode & FMODE_WRITE) {
-				if ((state->card->ac97_status & SPDIF_ON)) {	/* S/PDIF Enabled */
-					/* RELTEK ALC650 only support 48000, need to check that */
-					if (ali_valid_spdif_rate(codec, val)) {
-						if (codec_independent_spdif_locked > 0) {
-							ali_set_spdif_output(state, -1, 0);
-							stop_spdifout(state);
-							dmabuf->ready = 0;
-							/* I add test codec independent spdif out */
-							spin_lock_irqsave(&state->card->lock, flags);
-							ali_set_codecspdifout_rate(state, val);	// I modified
-							spin_unlock_irqrestore(&state->card->lock, flags);
-							/* Set S/PDIF transmitter rate. */
-							i_scr = inl(state->card->iobase + ALI_SCR);
-							if ((i_scr & 0x00300000) == 0x00100000) {
-								ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
-							} else {
-								if ((i_scr&0x00300000)  == 0x00200000)
-								{
-									ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
-								} else {
-									if ((i_scr & 0x00300000) == 0x00300000) {
-										ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
-									} else {
-										ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
-									}
-								}
-							}
-
-							if (!(state->card->ac97_status & SPDIF_ON)) {
-								val = dmabuf->rate;
-							}
-						} else {
-							if (controller_independent_spdif_locked > 0) 
-							{
-								stop_spdifout(state);
-								dmabuf->ready = 0;
-								spin_lock_irqsave(&state->card->lock, flags);
-								ali_set_spdifout_rate(state, controller_independent_spdif_locked);
-								spin_unlock_irqrestore(&state->card->lock, flags);
-							} else {
-								/* Set DAC rate */
-								ali_set_spdif_output(state, -1, 0);
-								stop_dac(state);
-								dmabuf->ready = 0;
-								spin_lock_irqsave(&state->card->lock, flags);
-								ali_set_dac_rate(state, val);
-								spin_unlock_irqrestore(&state->card->lock, flags);
-								/* Set S/PDIF transmitter rate. */
-								ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val);
-								if (!(state->card->ac97_status & SPDIF_ON))
-								{
-									val = dmabuf->rate;
-								}
-							}
-						}
-					} else {	/* Not a valid rate for S/PDIF, ignore it */
-						val = dmabuf->rate;
-					}
-				} else {
-					stop_dac(state);
-					dmabuf->ready = 0;
-					spin_lock_irqsave(&state->card->lock, flags);
-					ali_set_dac_rate(state, val);
-					spin_unlock_irqrestore(&state->card->lock, flags);
-				}
-			}
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(state);
-				dmabuf->ready = 0;
-				spin_lock_irqsave(&state->card->lock, flags);
-				ali_set_adc_rate(state, val);
-				spin_unlock_irqrestore(&state->card->lock, flags);
-			}
-		}
-		return put_user(dmabuf->rate, p);
-	case SNDCTL_DSP_STEREO:	/* set stereo or mono channel */
-#ifdef DEBUG
-		printk("SNDCTL_DSP_STEREO\n");
-#endif
-		if (dmabuf->enable & DAC_RUNNING) {
-			stop_dac(state);
-		}
-		if (dmabuf->enable & ADC_RUNNING) {
-			stop_adc(state);
-		}
-		if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
-			stop_spdifout(state);
-		}
-		if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
-			stop_spdifout(state);
-		}
-		return put_user(1, p);
-	case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if (codec_independent_spdif_locked > 0) {
-				if (!dmabuf->ready && (val = prog_dmabuf(state, 2)))
-					return val;
-			} else {
-				if (controller_independent_spdif_locked > 0) {
-					if (!dmabuf->ready && (val = prog_dmabuf(state, 3)))
-						return val;
-				} else {
-					if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
-						return val;
-				}
-			}
-		}
-
-		if (file->f_mode & FMODE_READ) {
-			if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
-				return val;
-		}
-#ifdef DEBUG
-		printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
-#endif
-		return put_user(dmabuf->userfragsize, p);
-	case SNDCTL_DSP_GETFMTS:	/* Returns a mask of supported sample format */
-#ifdef DEBUG
-		printk("SNDCTL_DSP_GETFMTS\n");
-#endif
-		return put_user(AFMT_S16_LE, p);
-	case SNDCTL_DSP_SETFMT:	/* Select sample format */
-#ifdef DEBUG
-		printk("SNDCTL_DSP_SETFMT\n");
-#endif
-		return put_user(AFMT_S16_LE, p);
-	case SNDCTL_DSP_CHANNELS:	// add support 4,6 channel 
-#ifdef DEBUG
-		printk("SNDCTL_DSP_CHANNELS\n");
-#endif
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val > 0) {
-			if (dmabuf->enable & DAC_RUNNING) {
-				stop_dac(state);
-			}
-			if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
-				stop_spdifout(state);
-			}
-			if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
-				stop_spdifout(state);
-			}
-			if (dmabuf->enable & ADC_RUNNING) {
-				stop_adc(state);
-			}
-		} else {
-			return put_user(state->card->channels, p);
-		}
-
-		i_scr = inl(state->card->iobase + ALI_SCR);
-		/* Current # of channels enabled */
-		if (i_scr & 0x00000100)
-			ret = 4;
-		else if (i_scr & 0x00000200)
-			ret = 6;
-		else
-			ret = 2;
-		switch (val) {
-		case 2:	/* 2 channels is always supported */
-			if (codec_independent_spdif_locked > 0) {
-				outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR));
-			} else
-				outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR));
-			/* Do we need to change mixer settings????  */
-			break;
-		case 4:	/* Supported on some chipsets, better check first */
-			if (codec_independent_spdif_locked > 0) {
-				outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR));
-			} else
-				outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR));
-			break;
-		case 6:	/* Supported on some chipsets, better check first */
-			if (codec_independent_spdif_locked > 0) {
-				outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR));
-			} else
-				outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR));
-			break;
-		default:	/* nothing else is ever supported by the chipset */
-			val = ret;
-			break;
-		}
-		return put_user(val, p);
-	case SNDCTL_DSP_POST:	/* the user has sent all data and is notifying us */
-		/* we update the swptr to the end of the last sg segment then return */
-#ifdef DEBUG
-		printk("SNDCTL_DSP_POST\n");
-#endif
-		if (codec_independent_spdif_locked > 0) {
-			if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING))
-				return 0;
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING))
-					return 0;
-			} else {
-				if (!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
-					return 0;
-			}
-		}
-		if ((dmabuf->swptr % dmabuf->fragsize) != 0) {
-			val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
-			dmabuf->swptr += val;
-			dmabuf->count += val;
-		}
-		return 0;
-	case SNDCTL_DSP_SUBDIVIDE:
-		if (dmabuf->subdivision)
-			return -EINVAL;
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-#ifdef DEBUG
-		printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
-#endif
-		dmabuf->subdivision = val;
-		dmabuf->ready = 0;
-		return 0;
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, p))
-			return -EFAULT;
-		dmabuf->ossfragsize = 1 << (val & 0xffff);
-		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-		if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
-			return -EINVAL;
-		/*
-		 * Bound the frag size into our allowed range of 256 - 4096
-		 */
-		if (dmabuf->ossfragsize < 256)
-			dmabuf->ossfragsize = 256;
-		else if (dmabuf->ossfragsize > 4096)
-			dmabuf->ossfragsize = 4096;
-		/*
-		 * The numfrags could be something reasonable, or it could
-		 * be 0xffff meaning "Give me as much as possible".  So,
-		 * we check the numfrags * fragsize doesn't exceed our
-		 * 64k buffer limit, nor is it less than our 8k minimum.
-		 * If it fails either one of these checks, then adjust the
-		 * number of fragments, not the size of them.  It's OK if
-		 * our number of fragments doesn't equal 32 or anything
-		 * like our hardware based number now since we are using
-		 * a different frag count for the hardware.  Before we get
-		 * into this though, bound the maxfrags to avoid overflow
-		 * issues.  A reasonable bound would be 64k / 256 since our
-		 * maximum buffer size is 64k and our minimum frag size is
-		 * 256.  On the other end, our minimum buffer size is 8k and
-		 * our maximum frag size is 4k, so the lower bound should
-		 * be 2.
-		 */
-		if (dmabuf->ossmaxfrags > 256)
-			dmabuf->ossmaxfrags = 256;
-		else if (dmabuf->ossmaxfrags < 2)
-			dmabuf->ossmaxfrags = 2;
-		val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-		while (val < 8192) {
-			val <<= 1;
-			dmabuf->ossmaxfrags <<= 1;
-		}
-		while (val > 65536) {
-			val >>= 1;
-			dmabuf->ossmaxfrags >>= 1;
-		}
-		dmabuf->ready = 0;
-#ifdef DEBUG
-		printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
-		       dmabuf->ossfragsize, dmabuf->ossmaxfrags);
-#endif
-		return 0;
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (codec_independent_spdif_locked > 0) {
-			if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
-				return val;
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
-					return val;
-			} else {
-				if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-					return val;
-			}
-		}
-		spin_lock_irqsave(&state->card->lock, flags);
-		ali_update_ptr(state);
-		abinfo.fragsize = dmabuf->userfragsize;
-		abinfo.fragstotal = dmabuf->userfrags;
-		if (dmabuf->mapped)
-			abinfo.bytes = dmabuf->dmasize;
-		else
-			abinfo.bytes = ali_get_free_write_space(state);
-		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-		printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n",
-		       abinfo.bytes, abinfo.fragsize, abinfo.fragments,
-		       abinfo.fragstotal);
-#endif
-		return copy_to_user(argp, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-	case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (codec_independent_spdif_locked > 0) {
-			if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
-				return val;
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
-					return val;
-			} else {
-				if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-					return val;
-			}
-		}
-		spin_lock_irqsave(&state->card->lock, flags);
-		val = ali_get_free_write_space(state);
-		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.ptr = dmabuf->hwptr;
-		cinfo.blocks = val / dmabuf->userfragsize;
-		if (codec_independent_spdif_locked > 0) {
-			if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
-				dmabuf->count += val;
-				dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-				__ali_update_lvi(state, 2);
-			}
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
-					dmabuf->count += val;
-					dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-					__ali_update_lvi(state, 3);
-				}
-			} else {
-				if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
-					dmabuf->count += val;
-					dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-					__ali_update_lvi(state, 0);
-				}
-			}
-		}
-		spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-		printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
-		       cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
-		return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT : 0;
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
-			return val;
-		spin_lock_irqsave(&state->card->lock, flags);
-		abinfo.bytes = ali_get_available_read_data(state);
-		abinfo.fragsize = dmabuf->userfragsize;
-		abinfo.fragstotal = dmabuf->userfrags;
-		abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-		printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n",
-		       abinfo.bytes, abinfo.fragsize, abinfo.fragments,
-		       abinfo.fragstotal);
-#endif
-		return copy_to_user(argp, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-			return val;
-		spin_lock_irqsave(&state->card->lock, flags);
-		val = ali_get_available_read_data(state);
-		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.blocks = val / dmabuf->userfragsize;
-		cinfo.ptr = dmabuf->hwptr;
-		if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
-			dmabuf->count -= val;
-			dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
-			__ali_update_lvi(state, 1);
-		}
-		spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-		printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
-		       cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
-		return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT: 0;
-	case SNDCTL_DSP_NONBLOCK:
-#ifdef DEBUG
-		printk("SNDCTL_DSP_NONBLOCK\n");
-#endif
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-	case SNDCTL_DSP_GETCAPS:
-#ifdef DEBUG
-		printk("SNDCTL_DSP_GETCAPS\n");
-#endif
-		return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
-				DSP_CAP_MMAP | DSP_CAP_BIND, p);
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-#ifdef DEBUG
-		printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
-#endif
-		return put_user(dmabuf->trigger, p);
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-#if defined(DEBUG) || defined(DEBUG_MMAP)
-		printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
-#endif
-		if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
-			stop_adc(state);
-		}
-		if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
-			stop_dac(state);
-		}
-		if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
-			stop_spdifout(state);
-		}
-		if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
-			stop_spdifout(state);
-		}
-		dmabuf->trigger = val;
-		if (val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
-			if (!dmabuf->write_channel) {
-				dmabuf->ready = 0;
-				dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
-				if (!dmabuf->write_channel)
-					return -EBUSY;
-			}
-			if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-				return ret;
-			if (dmabuf->mapped) {
-				spin_lock_irqsave(&state->card->lock, flags);
-				ali_update_ptr(state);
-				dmabuf->count = 0;
-				dmabuf->swptr = dmabuf->hwptr;
-				dmabuf->count = ali_get_free_write_space(state);
-				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
-				__ali_update_lvi(state, 0);
-				spin_unlock_irqrestore(&state->card->lock,
-						       flags);
-			} else
-				start_dac(state);
-		}
-		if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) {
-			if (!dmabuf->codec_spdifout_channel) {
-				dmabuf->ready = 0;
-				dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card);
-				if (!dmabuf->codec_spdifout_channel)
-					return -EBUSY;
-			}
-			if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
-				return ret;
-			if (dmabuf->mapped) {
-				spin_lock_irqsave(&state->card->lock, flags);
-				ali_update_ptr(state);
-				dmabuf->count = 0;
-				dmabuf->swptr = dmabuf->hwptr;
-				dmabuf->count = ali_get_free_write_space(state);
-				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
-				__ali_update_lvi(state, 2);
-				spin_unlock_irqrestore(&state->card->lock,
-						       flags);
-			} else
-				start_spdifout(state);
-		}
-		if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) {
-			if (!dmabuf->controller_spdifout_channel) {
-				dmabuf->ready = 0;
-				dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card);
-				if (!dmabuf->controller_spdifout_channel)
-					return -EBUSY;
-			}
-			if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
-				return ret;
-			if (dmabuf->mapped) {
-				spin_lock_irqsave(&state->card->lock, flags);
-				ali_update_ptr(state);
-				dmabuf->count = 0;
-				dmabuf->swptr = dmabuf->hwptr;
-				dmabuf->count = ali_get_free_write_space(state);
-				dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
-				__ali_update_lvi(state, 3);
-				spin_unlock_irqrestore(&state->card->lock, flags);
-			} else
-				start_spdifout(state);
-		}
-		if (val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
-			if (!dmabuf->read_channel) {
-				dmabuf->ready = 0;
-				dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
-				if (!dmabuf->read_channel)
-					return -EBUSY;
-			}
-			if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-				return ret;
-			if (dmabuf->mapped) {
-				spin_lock_irqsave(&state->card->lock,
-						  flags);
-				ali_update_ptr(state);
-				dmabuf->swptr = dmabuf->hwptr;
-				dmabuf->count = 0;
-				spin_unlock_irqrestore(&state->card->lock, flags);
-			}
-			ali_update_lvi(state, 1);
-			start_adc(state);
-		}
-		return 0;
-	case SNDCTL_DSP_SETDUPLEX:
-#ifdef DEBUG
-		printk("SNDCTL_DSP_SETDUPLEX\n");
-#endif
-		return -EINVAL;
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&state->card->lock, flags);
-		ali_update_ptr(state);
-		val = dmabuf->count;
-		spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
-		printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
-#endif
-		return put_user(val, p);
-	case SOUND_PCM_READ_RATE:
-#ifdef DEBUG
-		printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
-#endif
-		return put_user(dmabuf->rate, p);
-	case SOUND_PCM_READ_CHANNELS:
-#ifdef DEBUG
-		printk("SOUND_PCM_READ_CHANNELS\n");
-#endif
-		return put_user(2, p);
-	case SOUND_PCM_READ_BITS:
-#ifdef DEBUG
-		printk("SOUND_PCM_READ_BITS\n");
-#endif
-		return put_user(AFMT_S16_LE, p);
-	case SNDCTL_DSP_SETSPDIF:	/* Set S/PDIF Control register */
-#ifdef DEBUG
-		printk("SNDCTL_DSP_SETSPDIF\n");
-#endif
-		if (get_user(val, p))
-			return -EFAULT;
-		/* Check to make sure the codec supports S/PDIF transmitter */
-		if ((state->card->ac97_features & 4)) {
-			/* mask out the transmitter speed bits so the user can't set them */
-			val &= ~0x3000;
-			/* Add the current transmitter speed bits to the passed value */
-			ret = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
-			val |= (ret & 0x3000);
-			ali_ac97_set(codec, AC97_SPDIF_CONTROL, val);
-			if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) {
-				printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
-				return -EFAULT;
-			}
-		}
-#ifdef DEBUG
-		else
-			printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
-#endif
-		return put_user(val, p);
-	case SNDCTL_DSP_GETSPDIF:	/* Get S/PDIF Control register */
-#ifdef DEBUG
-		printk("SNDCTL_DSP_GETSPDIF\n");
-#endif
-		if (get_user(val, p))
-			return -EFAULT;
-		/* Check to make sure the codec supports S/PDIF transmitter */
-		if (!(state->card->ac97_features & 4)) {
-#ifdef DEBUG
-			printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
-#endif
-			val = 0;
-		} else {
-			val = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
-		}
-
-		return put_user(val, p);
-//end add support spdif out
-//add support 4,6 channel
-	case SNDCTL_DSP_GETCHANNELMASK:
-#ifdef DEBUG
-		printk("SNDCTL_DSP_GETCHANNELMASK\n");
-#endif
-		if (get_user(val, p))
-			return -EFAULT;
-		/* Based on AC'97 DAC support, not ICH hardware */
-		val = DSP_BIND_FRONT;
-		if (state->card->ac97_features & 0x0004)
-			val |= DSP_BIND_SPDIF;
-		if (state->card->ac97_features & 0x0080)
-			val |= DSP_BIND_SURR;
-		if (state->card->ac97_features & 0x0140)
-			val |= DSP_BIND_CENTER_LFE;
-		return put_user(val, p);
-	case SNDCTL_DSP_BIND_CHANNEL:
-#ifdef DEBUG
-		printk("SNDCTL_DSP_BIND_CHANNEL\n");
-#endif
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val == DSP_BIND_QUERY) {
-			val = DSP_BIND_FRONT;	/* Always report this as being enabled */
-			if (state->card->ac97_status & SPDIF_ON)
-				val |= DSP_BIND_SPDIF;
-			else {
-				if (state->card->ac97_status & SURR_ON)
-					val |= DSP_BIND_SURR;
-				if (state->card->
-				    ac97_status & CENTER_LFE_ON)
-					val |= DSP_BIND_CENTER_LFE;
-			}
-		} else {	/* Not a query, set it */
-			if (!(file->f_mode & FMODE_WRITE))
-				return -EINVAL;
-			if (dmabuf->enable == DAC_RUNNING) {
-				stop_dac(state);
-			}
-			if (val & DSP_BIND_SPDIF) {	/* Turn on SPDIF */
-				/*  Ok, this should probably define what slots
-				 *  to use. For now, we'll only set it to the
-				 *  defaults:
-				 * 
-				 *   non multichannel codec maps to slots 3&4
-				 *   2 channel codec maps to slots 7&8
-				 *   4 channel codec maps to slots 6&9
-				 *   6 channel codec maps to slots 10&11
-				 *
-				 *  there should be some way for the app to
-				 *  select the slot assignment.
-				 */
-				i_scr = inl(state->card->iobase + ALI_SCR);
-				if (codec_independent_spdif_locked > 0) {
-
-					if ((i_scr & 0x00300000) == 0x00100000) {
-						ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
-					} else {
-						if ((i_scr & 0x00300000) == 0x00200000) {
-							ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
-						} else {
-							if ((i_scr & 0x00300000) == 0x00300000) {
-								ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
-							}
-						}
-					}
-				} else {	/* codec spdif out (pcm out share ) */
-					ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate);	//I do not modify
-				}
-
-				if (!(state->card->ac97_status & SPDIF_ON))
-					val &= ~DSP_BIND_SPDIF;
-			} else {
-				int mask;
-				int channels;
-				/* Turn off S/PDIF if it was on */
-				if (state->card->ac97_status & SPDIF_ON)
-					ali_set_spdif_output(state, -1, 0);
-				mask =
-				    val & (DSP_BIND_FRONT | DSP_BIND_SURR |
-					   DSP_BIND_CENTER_LFE);
-				switch (mask) {
-				case DSP_BIND_FRONT:
-					channels = 2;
-					break;
-				case DSP_BIND_FRONT | DSP_BIND_SURR:
-					channels = 4;
-					break;
-				case DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE:
-					channels = 6;
-					break;
-				default:
-					val = DSP_BIND_FRONT;
-					channels = 2;
-					break;
-				}
-				ali_set_dac_channels(state, channels);
-				/* check that they really got turned on */
-				if (!state->card->ac97_status & SURR_ON)
-					val &= ~DSP_BIND_SURR;
-				if (!state->card->
-				    ac97_status & CENTER_LFE_ON)
-					val &= ~DSP_BIND_CENTER_LFE;
-			}
-		}
-		return put_user(val, p);
-	case SNDCTL_DSP_MAPINBUF:
-	case SNDCTL_DSP_MAPOUTBUF:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_WRITE_FILTER:
-	case SOUND_PCM_READ_FILTER:
-		return -EINVAL;
-	}
-	return -EINVAL;
-}
-
-static int ali_open(struct inode *inode, struct file *file)
-{
-	int i = 0;
-	struct ali_card *card = devs;
-	struct ali_state *state = NULL;
-	struct dmabuf *dmabuf = NULL;
-	unsigned int i_scr;
-	
-	/* find an available virtual channel (instance of /dev/dsp) */
-	
-	while (card != NULL) {
-
-		/*
-		 * If we are initializing and then fail, card could go
-		 * away unuexpectedly while we are in the for() loop.
-		 * So, check for card on each iteration before we check
-		 * for card->initializing to avoid a possible oops.
-		 * This usually only matters for times when the driver is
-		 * autoloaded by kmod.
-		 */
-		for (i = 0; i < 50 && card && card->initializing; i++) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ / 20);
-		}
-
-		for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
-			if (card->states[i] == NULL) {
-				state = card->states[i] = (struct ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL);
-				if (state == NULL)
-					return -ENOMEM;
-				memset(state, 0, sizeof(struct ali_state));
-				dmabuf = &state->dmabuf;
-				goto found_virt;
-			}
-		}
-		card = card->next;
-	}
-
-	/* no more virtual channel avaiable */
-	if (!state)
-		return -ENODEV;
-found_virt:
-	/* initialize the virtual channel */
-
-	state->virt = i;
-	state->card = card;
-	state->magic = ALI5455_STATE_MAGIC;
-	init_waitqueue_head(&dmabuf->wait);
-	mutex_init(&state->open_mutex);
-	file->private_data = state;
-	dmabuf->trigger = 0;
-	/* allocate hardware channels */
-	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;
-			return -EBUSY;
-		}
-		dmabuf->trigger |= PCM_ENABLE_INPUT;
-		ali_set_adc_rate(state, 8000);
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (codec_independent_spdif_locked > 0) {
-			if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) {
-				kfree(card->states[i]);
-				card->states[i] = NULL;
-				return -EBUSY;
-			}
-			dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
-			ali_set_codecspdifout_rate(state, codec_independent_spdif_locked);	//It must add
-			i_scr = inl(state->card->iobase + ALI_SCR);
-			if ((i_scr & 0x00300000) == 0x00100000) {
-				ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
-			} else {
-				if ((i_scr & 0x00300000) == 0x00200000) {
-					ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
-				} else {
-					if ((i_scr & 0x00300000) == 0x00300000) {
-						ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
-					} else {
-						ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
-					}
-				}
-
-			}
-		} else {
-			if (controller_independent_spdif_locked > 0) {
-				if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) {
-					kfree(card->states[i]);
-					card->states[i] = NULL;
-					return -EBUSY;
-				}
-				dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
-				ali_set_spdifout_rate(state, controller_independent_spdif_locked);
-			} else {
-				if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
-					kfree(card->states[i]);
-					card->states[i] = NULL;
-					return -EBUSY;
-				}
-				/* Initialize to 8kHz?  What if we don't support 8kHz? */
-				/*  Let's change this to check for S/PDIF stuff */
-
-				dmabuf->trigger |= PCM_ENABLE_OUTPUT;
-				if (codec_pcmout_share_spdif_locked) {
-					ali_set_dac_rate(state, codec_pcmout_share_spdif_locked);
-					ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked);
-				} else {
-					ali_set_dac_rate(state, 8000);
-				}
-			}
-
-		}
-	}
-
-	/* set default sample format. According to OSS Programmer's Guide  /dev/dsp
-	   should be default to unsigned 8-bits, mono, with sample rate 8kHz and
-	   /dev/dspW will accept 16-bits sample, but we don't support those so we
-	   set it immediately to stereo and 16bit, which is all we do support */
-	dmabuf->fmt |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO;
-	dmabuf->ossfragsize = 0;
-	dmabuf->ossmaxfrags = 0;
-	dmabuf->subdivision = 0;
-	state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
-	outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
-	return nonseekable_open(inode, file);
-}
-
-static int ali_release(struct inode *inode, struct file *file)
-{
-	struct ali_state *state = (struct ali_state *) file->private_data;
-	struct ali_card *card = state->card;
-	struct dmabuf *dmabuf = &state->dmabuf;
-	unsigned long flags;
-	lock_kernel();
-	
-	/* stop DMA state machine and free DMA buffers/channels */
-	if (dmabuf->trigger & PCM_ENABLE_OUTPUT)
-		drain_dac(state, 0);
-
-	if (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)
-		drain_spdifout(state, 0);
-	
-	if (dmabuf->trigger & PCM_ENABLE_INPUT)
-		stop_adc(state);
-	
-	spin_lock_irqsave(&card->lock, flags);
-	dealloc_dmabuf(state);
-	if (file->f_mode & FMODE_WRITE) {
-		if (codec_independent_spdif_locked > 0) {
-			state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num);
-		} else {
-			if (controller_independent_spdif_locked > 0)
-				state->card->free_pcm_channel(state->card,
-							      dmabuf->controller_spdifout_channel->num);
-			else state->card->free_pcm_channel(state->card,
-							      dmabuf->write_channel->num);
-		}
-	}
-	if (file->f_mode & FMODE_READ)
-		state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
-
-	state->card->states[state->virt] = NULL;
-	kfree(state);
-	spin_unlock_irqrestore(&card->lock, flags);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const */ struct file_operations ali_audio_fops = {
-	.owner		= THIS_MODULE, 
-	.llseek		= no_llseek, 
-	.read		= ali_read,
-	.write		= ali_write, 
-	.poll		= ali_poll,
-	.ioctl		= ali_ioctl,
-	.mmap		= ali_mmap,
-	.open		= ali_open,
-	.release	= ali_release,
-};
-
-/* Read AC97 codec registers */
-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg)
-{
-	struct ali_card *card = dev->private_data;
-	int count1 = 100;
-	char val;
-	unsigned short int data = 0, count, addr1, addr2 = 0;
-
-	spin_lock(&card->ac97_lock);
-	while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
-		udelay(1);
-
-	addr1 = reg;
-	reg |= 0x0080;
-	for (count = 0; count < 0x7f; count++) {
-		val = inb(card->iobase + ALI_CSPSR);
-		if (val & 0x08)
-			break;
-	}
-	if (count == 0x7f)
-	{
-		spin_unlock(&card->ac97_lock);
-		return -1;
-	}
-	outw(reg, (card->iobase + ALI_CPR) + 2);
-	for (count = 0; count < 0x7f; count++) {
-		val = inb(card->iobase + ALI_CSPSR);
-		if (val & 0x02) {
-			data = inw(card->iobase + ALI_SPR);
-			addr2 = inw((card->iobase + ALI_SPR) + 2);
-			break;
-		}
-	}
-	spin_unlock(&card->ac97_lock);
-	if (count == 0x7f)
-		return -1;
-	if (addr2 != addr1)
-		return -1;
-	return ((u16) data);
-}
-
-/* write ac97 codec register   */
-
-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
-{
-	struct ali_card *card = dev->private_data;
-	int count1 = 100;
-	char val;
-	unsigned short int count;
-
-	spin_lock(&card->ac97_lock);
-	while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
-		udelay(1);
-
-	for (count = 0; count < 0x7f; count++) {
-		val = inb(card->iobase + ALI_CSPSR);
-		if (val & 0x08)
-			break;
-	}
-	if (count == 0x7f) {
-		printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
-		spin_unlock(&card->ac97_lock);
-		return;
-	}
-	outw(data, (card->iobase + ALI_CPR));
-	outb(reg, (card->iobase + ALI_CPR) + 2);
-	for (count = 0; count < 0x7f; count++) {
-		val = inb(card->iobase + ALI_CSPSR);
-		if (val & 0x01)
-			break;
-	}
-	spin_unlock(&card->ac97_lock);
-	if (count == 0x7f)
-		printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
-	return;
-}
-
-/* OSS /dev/mixer file operation methods */
-
-static int ali_open_mixdev(struct inode *inode, struct file *file)
-{
-	int i;
-	int minor = iminor(inode);
-	struct ali_card *card = devs;
-	for (card = devs; card != NULL; card = card->next) {
-		/*
-		 * If we are initializing and then fail, card could go
-		 * away unuexpectedly while we are in the for() loop.
-		 * So, check for card on each iteration before we check
-		 * for card->initializing to avoid a possible oops.
-		 * This usually only matters for times when the driver is
-		 * autoloaded by kmod.
-		 */
-		for (i = 0; i < 50 && card && card->initializing; i++) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(HZ / 20);
-		}
-		for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
-			if (card->ac97_codec[i] != NULL
-			    && card->ac97_codec[i]->dev_mixer == minor) {
-				file->private_data = card->ac97_codec[i];
-				return nonseekable_open(inode, file);
-			}
-	}
-	return -ENODEV;
-}
-
-static int ali_ioctl_mixdev(struct inode *inode,
-			    struct file *file,
-			    unsigned int cmd, unsigned long arg)
-{
-	struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
-	return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const */ struct file_operations ali_mixer_fops = {
-	.owner	= THIS_MODULE, 
-	.llseek	= no_llseek, 
-	.ioctl	= ali_ioctl_mixdev,
-	.open	= ali_open_mixdev,
-};
-
-/* AC97 codec initialisation.  These small functions exist so we don't
-   duplicate code between module init and apm resume */
-
-static inline int ali_ac97_exists(struct ali_card *card, int ac97_number)
-{
-	unsigned int i = 1;
-	u32 reg = inl(card->iobase + ALI_RTSR);
-	if (ac97_number) {
-		while (i < 100) {
-
-			reg = inl(card->iobase + ALI_RTSR);
-			if (reg & 0x40) {
-				break;
-			} else {
-				outl(reg | 0x00000040,
-				     card->iobase + 0x34);
-				udelay(1);
-			}
-			i++;
-		}
-
-	} else {
-		while (i < 100) {
-			reg = inl(card->iobase + ALI_RTSR);
-			if (reg & 0x80) {
-				break;
-			} else {
-				outl(reg | 0x00000080,
-				     card->iobase + 0x34);
-				udelay(1);
-			}
-			i++;
-		}
-	}
-
-	if (ac97_number)
-		return reg & 0x40;
-	else
-		return reg & 0x80;
-}
-
-static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec)
-{
-	ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
-	ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800);
-	return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1);
-}
-
-
-static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec)
-{
-	/* Returns 0 on failure */
-	int i;
-	u16 addr;
-	if (ac97_probe_codec(codec) == 0)
-		return 0;
-	/* ac97_probe_codec is success ,then begin to init codec */
-	ali_ac97_set(codec, AC97_RESET, 0xffff);
-	if (card->channel[0].used == 1) {
-		ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
-		ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808);
-		ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
-	}
-
-	if (card->channel[2].used == 1)	//if MICin then init codec
-	{
-		ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
-		ali_ac97_set(codec, AC97_MIC_VOL, 0x8808);
-		ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
-		ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000);
-	}
-
-	ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000);
-	ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000);
-	ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000);
-	ali_ac97_set(codec, AC97_CD_VOL, 0x0808);
-	ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808);
-	ali_ac97_set(codec, AC97_AUX_VOL, 0x0808);
-	ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048);
-	ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000);
-	ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX);
-	ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000);
-	ali_ac97_set(codec, 0x38, 0x0000);
-	addr = ali_ac97_get(codec, 0x2a);
-	ali_ac97_set(codec, 0x2a, addr | 0x0001);
-	addr = ali_ac97_get(codec, 0x2a);
-	addr = ali_ac97_get(codec, 0x28);
-	ali_ac97_set(codec, 0x2c, 0xbb80);
-	addr = ali_ac97_get(codec, 0x2c);
-	/* power it all up */
-	ali_ac97_set(codec, AC97_POWER_CONTROL,
-		     ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
-	/* wait for analog ready */
-	for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) {
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		schedule_timeout(HZ / 20);
-	}
-	/* FIXME !! */
-	i++;
-	return i;
-}
-
-
-/* I clone ali5455(2.4.7 )  not clone i810_audio(2.4.18)  */
-
-static int ali_reset_5455(struct ali_card *card)
-{
-	outl(0x80000003, card->iobase + ALI_SCR);
-	outl(0x83838383, card->iobase + ALI_FIFOCR1);
-	outl(0x83838383, card->iobase + ALI_FIFOCR2);
-	if (controller_pcmout_share_spdif_locked > 0) {
-		outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
-		     card->iobase + ALI_SPDIFICS);
-		outl(0x0408000a, card->iobase + ALI_INTERFACECR);
-	} else {
-		if (codec_independent_spdif_locked > 0) {
-			outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR);	// now I select slot 7 & 8
-			outl(0x00200000, card->iobase + ALI_INTERFACECR);	//enable codec independent spdifout 
-		} else
-			outl(0x04080002, card->iobase + ALI_INTERFACECR);
-	}
-
-	outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
-	outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
-	if (controller_independent_spdif_locked > 0)
-		outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
-		     card->iobase + ALI_SPDIFICS);
-	return 1;
-}
-
-
-static int ali_ac97_random_init_stuff(struct ali_card
-				      *card)
-{
-	u32 reg = inl(card->iobase + ALI_SCR);
-	int i = 0;
-	reg = inl(card->iobase + ALI_SCR);
-	if ((reg & 2) == 0)	/* Cold required */
-		reg |= 2;
-	else
-		reg |= 1;	/* Warm */
-	reg &= ~0x80000000;	/* ACLink on */
-	outl(reg, card->iobase + ALI_SCR);
-
-	while (i < 10) {
-		if ((inl(card->iobase + 0x18) & (1 << 1)) == 0)
-			break;
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(HZ / 20);
-		i++;
-	}
-	if (i == 10) {
-		printk(KERN_ERR "ali_audio: AC'97 reset failed.\n");
-		return 0;
-	}
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	schedule_timeout(HZ / 2);
-	return 1;
-}
-
-/* AC97 codec initialisation. */
-
-static int __devinit ali_ac97_init(struct ali_card *card)
-{
-	int num_ac97 = 0;
-	int total_channels = 0;
-	struct ac97_codec *codec;
-	u16 eid;
-
-	if (!ali_ac97_random_init_stuff(card))
-		return 0;
-
-	/* Number of channels supported */
-	/* What about the codec?  Just because the ICH supports */
-	/* multiple channels doesn't mean the codec does.       */
-	/* we'll have to modify this in the codec section below */
-	/* to reflect what the codec has.                       */
-	/* ICH and ICH0 only support 2 channels so don't bother */
-	/* to check....                                         */
-	inl(card->iobase + ALI_CPR);
-	card->channels = 2;
-
-	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-
-		/* Assume codec isn't available until we go through the
-		 * gauntlet below */
-		card->ac97_codec[num_ac97] = NULL;
-		/* The ICH programmer's reference says you should   */
-		/* check the ready status before probing. So we chk */
-		/*   What do we do if it's not ready?  Wait and try */
-		/*   again, or abort?                               */
-		if (!ali_ac97_exists(card, num_ac97)) {
-			if (num_ac97 == 0)
-				printk(KERN_ERR "ali_audio: Primary codec not ready.\n");
-			break;
-		}
-
-		if ((codec = ac97_alloc_codec()) == NULL)
-			return -ENOMEM;
-		/* initialize some basic codec information, other fields will be filled
-		   in ac97_probe_codec */
-		codec->private_data = card;
-		codec->id = num_ac97;
-		codec->codec_read = ali_ac97_get;
-		codec->codec_write = ali_ac97_set;
-		if (!ali_ac97_probe_and_powerup(card, codec)) {
-			printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready",
-			     num_ac97);
-			kfree(codec);
-			break;	/* it didn't work */
-		}
-		
-		/* Store state information about S/PDIF transmitter */
-		card->ac97_status = 0;
-		/* Don't attempt to get eid until powerup is complete */
-		eid = ali_ac97_get(codec, AC97_EXTENDED_ID);
-		if (eid == 0xFFFF) {
-			printk(KERN_ERR "ali_audio: no codec attached ?\n");
-			kfree(codec);
-			break;
-		}
-
-		card->ac97_features = eid;
-		/* Now check the codec for useful features to make up for
-		   the dumbness of the ali5455 hardware engine */
-		if (!(eid & 0x0001))
-			printk(KERN_WARNING
-			       "ali_audio: only 48Khz playback available.\n");
-		else {
-			if (!ali_ac97_enable_variable_rate(codec)) {
-				printk(KERN_WARNING
-				       "ali_audio: Codec refused to allow VRA, using 48Khz only.\n");
-				card->ac97_features &= ~1;
-			}
-		}
-
-		/* Determine how many channels the codec(s) support   */
-		/*   - The primary codec always supports 2            */
-		/*   - If the codec supports AMAP, surround DACs will */
-		/*     automaticlly get assigned to slots.            */
-		/*     * Check for surround DACs and increment if     */
-		/*       found.                                       */
-		/*   - Else check if the codec is revision 2.2        */
-		/*     * If surround DACs exist, assign them to slots */
-		/*       and increment channel count.                 */
-
-		/* All of this only applies to ICH2 and above. ICH    */
-		/* and ICH0 only support 2 channels.  ICH2 will only  */
-		/* support multiple codecs in a "split audio" config. */
-		/* as described above.                                */
-
-		/* TODO: Remove all the debugging messages!           */
-
-		if ((eid & 0xc000) == 0)	/* primary codec */
-			total_channels += 2;
-		if ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) {
-			printk(KERN_ERR "ali_audio: couldn't register mixer!\n");
-			kfree(codec);
-			break;
-		}
-		card->ac97_codec[num_ac97] = codec;
-	}
-	/* pick the minimum of channels supported by ICHx or codec(s) */
-	card->channels = (card->channels > total_channels) ? total_channels : card->channels;
-	return num_ac97;
-}
-
-static void __devinit ali_configure_clocking(void)
-{
-	struct ali_card *card;
-	struct ali_state *state;
-	struct dmabuf *dmabuf;
-	unsigned int i, offset, new_offset;
-	unsigned long flags;
-	card = devs;
-
-	/* We could try to set the clocking for multiple cards, but can you even have
-	 * more than one ali in a machine?  Besides, clocking is global, so unless
-	 * someone actually thinks more than one ali in a machine is possible and
-	 * decides to rewrite that little bit, setting the rate for more than one card
-	 * is a waste of time.
-	 */
-	if (card != NULL) {
-		state = card->states[0] = (struct ali_state *)
-		    kmalloc(sizeof(struct ali_state), GFP_KERNEL);
-		if (state == NULL)
-			return;
-		memset(state, 0, sizeof(struct ali_state));
-		dmabuf = &state->dmabuf;
-		dmabuf->write_channel = card->alloc_pcm_channel(card);
-		state->virt = 0;
-		state->card = card;
-		state->magic = ALI5455_STATE_MAGIC;
-		init_waitqueue_head(&dmabuf->wait);
-		mutex_init(&state->open_mutex);
-		dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT;
-		dmabuf->trigger = PCM_ENABLE_OUTPUT;
-		ali_set_dac_rate(state, 48000);
-		if (prog_dmabuf(state, 0) != 0)
-			goto config_out_nodmabuf;
-		
-		if (dmabuf->dmasize < 16384)
-			goto config_out;
-		
-		dmabuf->count = dmabuf->dmasize;
-		outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI);
-
-		local_irq_save(flags);
-		start_dac(state);
-		offset = ali_get_dma_addr(state, 0);
-		mdelay(50);
-		new_offset = ali_get_dma_addr(state, 0);
-		stop_dac(state);
-		
-		outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR);
-		local_irq_restore(flags);
-
-		i = new_offset - offset;
-
-		if (i == 0)
-			goto config_out;
-		i = i / 4 * 20;
-		if (i > 48500 || i < 47500) {
-			clocking = clocking * clocking / i;
-		}
-config_out:
-		dealloc_dmabuf(state);
-config_out_nodmabuf:
-		state->card->free_pcm_channel(state->card, state->dmabuf. write_channel->num);
-		kfree(state);
-		card->states[0] = NULL;
-	}
-}
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered 
-   until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
-
-static int __devinit ali_probe(struct pci_dev *pci_dev,
-			       const struct pci_device_id *pci_id)
-{
-	struct ali_card *card;
-	if (pci_enable_device(pci_dev))
-		return -EIO;
-	if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) {
-		printk(KERN_ERR "ali5455: architecture does not support"
-		       " 32bit PCI busmaster DMA\n");
-		return -ENODEV;
-	}
-
-	if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) {
-		printk(KERN_ERR "ali_audio: out of memory\n");
-		return -ENOMEM;
-	}
-	memset(card, 0, sizeof(*card));
-	card->initializing = 1;
-	card->iobase = pci_resource_start(pci_dev, 0);
-	card->pci_dev = pci_dev;
-	card->pci_id = pci_id->device;
-	card->irq = pci_dev->irq;
-	card->next = devs;
-	card->magic = ALI5455_CARD_MAGIC;
-#ifdef CONFIG_PM
-	card->pm_suspended = 0;
-#endif
-	spin_lock_init(&card->lock);
-	spin_lock_init(&card->ac97_lock);
-	devs = card;
-	pci_set_master(pci_dev);
-	printk(KERN_INFO "ali: %s found at IO 0x%04lx, IRQ %d\n",
-	       card_names[pci_id->driver_data], card->iobase, card->irq);
-	card->alloc_pcm_channel = ali_alloc_pcm_channel;
-	card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
-	card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel;
-	card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel;
-	card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel;
-	card->free_pcm_channel = ali_free_pcm_channel;
-	card->channel[0].offset = 0;
-	card->channel[0].port = 0x40;
-	card->channel[0].num = 0;
-	card->channel[1].offset = 0;
-	card->channel[1].port = 0x50;
-	card->channel[1].num = 1;
-	card->channel[2].offset = 0;
-	card->channel[2].port = 0x60;
-	card->channel[2].num = 2;
-	card->channel[3].offset = 0;
-	card->channel[3].port = 0x70;
-	card->channel[3].num = 3;
-	card->channel[4].offset = 0;
-	card->channel[4].port = 0xb0;
-	card->channel[4].num = 4;
-	/* claim our iospace and irq */
-	request_region(card->iobase, 256, card_names[pci_id->driver_data]);
-	if (request_irq(card->irq, &ali_interrupt, IRQF_SHARED,
-			card_names[pci_id->driver_data], card)) {
-		printk(KERN_ERR "ali_audio: unable to allocate irq %d\n",
-		       card->irq);
-		release_region(card->iobase, 256);
-		kfree(card);
-		return -ENODEV;
-	}
-
-	if (ali_reset_5455(card) <= 0) {
-		unregister_sound_dsp(card->dev_audio);
-		release_region(card->iobase, 256);
-		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
-	}
-
-	/* initialize AC97 codec and register /dev/mixer */
-	if (ali_ac97_init(card) < 0) {
-		release_region(card->iobase, 256);
-		free_irq(card->irq, card);
-		kfree(card);
-		return -ENODEV;
-	}
-	
-	pci_set_drvdata(pci_dev, card);
-	
-	if (clocking == 0) {
-		clocking = 48000;
-		ali_configure_clocking();
-	}
-
-	/* register /dev/dsp */
-	if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) {
-		int i;
-		printk(KERN_ERR"ali_audio: couldn't register DSP device!\n");
-		release_region(card->iobase, 256);
-		free_irq(card->irq, card);
-		for (i = 0; i < NR_AC97; i++)
-			if (card->ac97_codec[i] != NULL) {
-				unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
-				kfree(card->ac97_codec[i]);
-			}
-		kfree(card);
-		return -ENODEV;
-	}
-	card->initializing = 0;
-	return 0;
-}
-
-static void __devexit ali_remove(struct pci_dev *pci_dev)
-{
-	int i;
-	struct ali_card *card = pci_get_drvdata(pci_dev);
-	/* free hardware resources */
-	free_irq(card->irq, devs);
-	release_region(card->iobase, 256);
-	/* unregister audio devices */
-	for (i = 0; i < NR_AC97; i++)
-		if (card->ac97_codec[i] != NULL) {
-			unregister_sound_mixer(card->ac97_codec[i]->
-					       dev_mixer);
-			ac97_release_codec(card->ac97_codec[i]);
-			card->ac97_codec[i] = NULL;
-		}
-	unregister_sound_dsp(card->dev_audio);
-	kfree(card);
-}
-
-#ifdef CONFIG_PM
-static int ali_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
-{
-	struct ali_card *card = pci_get_drvdata(dev);
-	struct ali_state *state;
-	unsigned long flags;
-	struct dmabuf *dmabuf;
-	int i, num_ac97;
-
-	if (!card)
-		return 0;
-	spin_lock_irqsave(&card->lock, flags);
-	card->pm_suspended = 1;
-	for (i = 0; i < NR_HW_CH; i++) {
-		state = card->states[i];
-		if (!state)
-			continue;
-		/* this happens only if there are open files */
-		dmabuf = &state->dmabuf;
-		if (dmabuf->enable & DAC_RUNNING ||
-		    (dmabuf->count
-		     && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
-			state->pm_saved_dac_rate = dmabuf->rate;
-			stop_dac(state);
-		} else {
-			state->pm_saved_dac_rate = 0;
-		}
-		if (dmabuf->enable & ADC_RUNNING) {
-			state->pm_saved_adc_rate = dmabuf->rate;
-			stop_adc(state);
-		} else {
-			state->pm_saved_adc_rate = 0;
-		}
-		dmabuf->ready = 0;
-		dmabuf->swptr = dmabuf->hwptr = 0;
-		dmabuf->count = dmabuf->total_bytes = 0;
-	}
-
-	spin_unlock_irqrestore(&card->lock, flags);
-	/* save mixer settings */
-	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-		struct ac97_codec *codec = card->ac97_codec[num_ac97];
-		if (!codec)
-			continue;
-		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			if ((supported_mixer(codec, i)) && (codec->read_mixer)) {
-				card->pm_saved_mixer_settings[i][num_ac97] = codec->read_mixer(codec, i);
-			}
-		}
-	}
-	pci_save_state(dev);	/* XXX do we need this? */
-	pci_disable_device(dev);	/* disable busmastering */
-	pci_set_power_state(dev, 3);	/* Zzz. */
-	return 0;
-}
-
-
-static int ali_pm_resume(struct pci_dev *dev)
-{
-	int num_ac97, i = 0;
-	struct ali_card *card = pci_get_drvdata(dev);
-	pci_enable_device(dev);
-	pci_restore_state(dev);
-	/* observation of a toshiba portege 3440ct suggests that the 
-	   hardware has to be more or less completely reinitialized from
-	   scratch after an apm suspend.  Works For Me.   -dan */
-	ali_ac97_random_init_stuff(card);
-	for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-		struct ac97_codec *codec = card->ac97_codec[num_ac97];
-		/* check they haven't stolen the hardware while we were
-		   away */
-		if (!codec || !ali_ac97_exists(card, num_ac97)) {
-			if (num_ac97)
-				continue;
-			else
-				BUG();
-		}
-		if (!ali_ac97_probe_and_powerup(card, codec))
-			BUG();
-		if ((card->ac97_features & 0x0001)) {
-			/* at probe time we found we could do variable
-			   rates, but APM suspend has made it forget
-			   its magical powers */
-			if (!ali_ac97_enable_variable_rate(codec))
-				BUG();
-		}
-		/* we lost our mixer settings, so restore them */
-		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			if (supported_mixer(codec, i)) {
-				int val = card->pm_saved_mixer_settings[i][num_ac97];
-				codec->mixer_state[i] = val;
-				codec->write_mixer(codec, i,
-						   (val & 0xff),
-						   ((val >> 8) & 0xff));
-			}
-		}
-	}
-
-	/* we need to restore the sample rate from whatever it was */
-	for (i = 0; i < NR_HW_CH; i++) {
-		struct ali_state *state = card->states[i];
-		if (state) {
-			if (state->pm_saved_adc_rate)
-				ali_set_adc_rate(state, state->pm_saved_adc_rate);
-			if (state->pm_saved_dac_rate)
-				ali_set_dac_rate(state, state->pm_saved_dac_rate);
-		}
-	}
-
-	card->pm_suspended = 0;
-	/* any processes that were reading/writing during the suspend
-	   probably ended up here */
-	for (i = 0; i < NR_HW_CH; i++) {
-		struct ali_state *state = card->states[i];
-		if (state)
-			wake_up(&state->dmabuf.wait);
-	}
-	return 0;
-}
-#endif				/* CONFIG_PM */
-
-MODULE_AUTHOR("");
-MODULE_DESCRIPTION("ALI 5455 audio support");
-MODULE_LICENSE("GPL");
-module_param(clocking, int, 0);
-/* FIXME: bool? */
-module_param(strict_clocking, uint, 0);
-module_param(codec_pcmout_share_spdif_locked, uint, 0);
-module_param(codec_independent_spdif_locked, uint, 0);
-module_param(controller_pcmout_share_spdif_locked, uint, 0);
-module_param(controller_independent_spdif_locked, uint, 0);
-#define ALI5455_MODULE_NAME "ali5455"
-static struct pci_driver ali_pci_driver = {
-	.name		= ALI5455_MODULE_NAME,
-	.id_table	= ali_pci_tbl,
-	.probe		= ali_probe,
-	.remove		= __devexit_p(ali_remove),
-#ifdef CONFIG_PM
-	.suspend	= ali_pm_suspend,
-	.resume		= ali_pm_resume,
-#endif				/* CONFIG_PM */
-};
-
-static int __init ali_init_module(void)
-{
-	printk(KERN_INFO "ALI 5455 + AC97 Audio, version "
-	       DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
-	if (codec_independent_spdif_locked > 0) {
-		if (codec_independent_spdif_locked == 32000
-		    || codec_independent_spdif_locked == 44100
-		    || codec_independent_spdif_locked == 48000) {
-			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked);
-		} else {
-			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
-			codec_independent_spdif_locked = 0;
-		}
-	}
-	if (controller_independent_spdif_locked > 0) {
-		if (controller_independent_spdif_locked == 32000
-		    || controller_independent_spdif_locked == 44100
-		    || controller_independent_spdif_locked == 48000) {
-			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked);
-		} else {
-			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
-			controller_independent_spdif_locked = 0;
-		}
-	}
-
-	if (codec_pcmout_share_spdif_locked > 0) {
-		if (codec_pcmout_share_spdif_locked == 32000
-		    || codec_pcmout_share_spdif_locked == 44100
-		    || codec_pcmout_share_spdif_locked == 48000) {
-			printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked);
-		} else {
-			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
-			codec_pcmout_share_spdif_locked = 0;
-		}
-	}
-	if (controller_pcmout_share_spdif_locked > 0) {
-		if (controller_pcmout_share_spdif_locked == 32000
-		    || controller_pcmout_share_spdif_locked == 44100
-		    || controller_pcmout_share_spdif_locked == 48000) {
-			printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked);
-		} else {
-			printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
-			controller_pcmout_share_spdif_locked = 0;
-		}
-	}
-	return pci_register_driver(&ali_pci_driver);
-}
-
-static void __exit ali_cleanup_module(void)
-{
-	pci_unregister_driver(&ali_pci_driver);
-}
-
-module_init(ali_init_module);
-module_exit(ali_cleanup_module);
-/*
-Local Variables:
-c-basic-offset: 8
-End:
-*/
diff --git a/sound/oss/au1000.c b/sound/oss/au1000.c
deleted file mode 100644
index e379623..0000000
--- a/sound/oss/au1000.c
+++ /dev/null
@@ -1,2216 +0,0 @@
-/*
- *      au1000.c  --  Sound driver for Alchemy Au1000 MIPS Internet Edge
- *                    Processor.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *         	stevel@mvista.com or source@mvista.com
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
- *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
- *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  You should have received a copy of the  GNU General Public License along
- *  with this program; if not, write  to the Free Software Foundation, Inc.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * Module command line parameters:
- *
- *  Supported devices:
- *  /dev/dsp    standard OSS /dev/dsp device
- *  /dev/mixer  standard OSS /dev/mixer device
- *
- * Notes:
- *
- *  1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are
- *     taken, slightly modified or not at all, from the ES1371 driver,
- *     so refer to the credits in es1371.c for those. The rest of the
- *     code (probe, open, read, write, the ISR, etc.) is new.
- *
- *  Revision history
- *    06.27.2001  Initial version
- *    03.20.2002  Added mutex locks around read/write methods, to prevent
- *                simultaneous access on SMP or preemptible kernels. Also
- *                removed the counter/pointer fragment aligning at the end
- *                of read/write methods [stevel].
- *    03.21.2002  Add support for coherent DMA on the audio read/write DMA
- *                channels [stevel].
- *
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/init.h>
-#include <linux/page-flags.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1000_dma.h>
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#undef AU1000_DEBUG
-#undef AU1000_VERBOSE_DEBUG
-
-#define AU1000_MODULE_NAME "Au1000 audio"
-#define PFX AU1000_MODULE_NAME
-
-#ifdef AU1000_DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
-
-
-/* misc stuff */
-#define POLL_COUNT   0x5000
-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
-
-/* Boot options */
-static int      vra = 0;	// 0 = no VRA, 1 = use VRA if codec supports it
-module_param(vra, bool, 0);
-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
-
-
-/* --------------------------------------------------------------------- */
-
-struct au1000_state {
-	/* soundcore stuff */
-	int             dev_audio;
-
-#ifdef AU1000_DEBUG
-	/* debug /proc entry */
-	struct proc_dir_entry *ps;
-	struct proc_dir_entry *ac97_ps;
-#endif				/* AU1000_DEBUG */
-
-	struct ac97_codec codec;
-	unsigned        codec_base_caps;// AC'97 reg 00h, "Reset Register"
-	unsigned        codec_ext_caps;	// AC'97 reg 28h, "Extended Audio ID"
-	int             no_vra;	// do not use VRA
-
-	spinlock_t      lock;
-	struct mutex open_mutex;
-	struct mutex sem;
-	mode_t          open_mode;
-	wait_queue_head_t open_wait;
-
-	struct dmabuf {
-		unsigned int    dmanr;	// DMA Channel number
-		unsigned        sample_rate;	// Hz
-		unsigned src_factor;     // SRC interp/decimation (no vra)
-		unsigned        sample_size;	// 8 or 16
-		int             num_channels;	// 1 = mono, 2 = stereo, 4, 6
-		int dma_bytes_per_sample;// DMA bytes per audio sample frame
-		int user_bytes_per_sample;// User bytes per audio sample frame
-		int cnt_factor;          // user-to-DMA bytes per audio
-		//  sample frame
-		void           *rawbuf;
-		dma_addr_t      dmaaddr;
-		unsigned        buforder;
-		unsigned numfrag;        // # of DMA fragments in DMA buffer
-		unsigned        fragshift;
-		void           *nextIn;	// ptr to next-in to DMA buffer
-		void           *nextOut;// ptr to next-out from DMA buffer
-		int             count;	// current byte count in DMA buffer
-		unsigned        total_bytes;	// total bytes written or read
-		unsigned        error;	// over/underrun
-		wait_queue_head_t wait;
-		/* redundant, but makes calculations easier */
-		unsigned fragsize;       // user perception of fragment size
-		unsigned dma_fragsize;   // DMA (real) fragment size
-		unsigned dmasize;        // Total DMA buffer size
-		//   (mult. of DMA fragsize)
-		/* OSS stuff */
-		unsigned        mapped:1;
-		unsigned        ready:1;
-		unsigned        stopped:1;
-		unsigned        ossfragshift;
-		int             ossmaxfrags;
-		unsigned        subdivision;
-	} dma_dac      , dma_adc;
-} au1000_state;
-
-/* --------------------------------------------------------------------- */
-
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned        r = 0;
-
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void au1000_delay(int msec)
-{
-	unsigned long   tmo;
-	signed long     tmo2;
-
-	if (in_interrupt())
-		return;
-
-	tmo = jiffies + (msec * HZ) / 1000;
-	for (;;) {
-		tmo2 = tmo - jiffies;
-		if (tmo2 <= 0)
-			break;
-		schedule_timeout(tmo2);
-	}
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static u16 rdcodec(struct ac97_codec *codec, u8 addr)
-{
-	struct au1000_state *s = (struct au1000_state *)codec->private_data;
-	unsigned long   flags;
-	u32             cmd;
-	u16             data;
-	int             i;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	for (i = 0; i < POLL_COUNT; i++)
-		if (!(au_readl(AC97C_STATUS) & AC97C_CP))
-			break;
-	if (i == POLL_COUNT)
-		err("rdcodec: codec cmd pending expired!");
-
-	cmd = (u32) addr & AC97C_INDEX_MASK;
-	cmd |= AC97C_READ;	// read command
-	au_writel(cmd, AC97C_CMD);
-
-	/* now wait for the data */
-	for (i = 0; i < POLL_COUNT; i++)
-		if (!(au_readl(AC97C_STATUS) & AC97C_CP))
-			break;
-	if (i == POLL_COUNT) {
-		err("rdcodec: read poll expired!");
-		return 0;
-	}
-
-	data = au_readl(AC97C_CMD) & 0xffff;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-
-	return data;
-}
-
-
-static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
-	struct au1000_state *s = (struct au1000_state *)codec->private_data;
-	unsigned long   flags;
-	u32             cmd;
-	int             i;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	for (i = 0; i < POLL_COUNT; i++)
-		if (!(au_readl(AC97C_STATUS) & AC97C_CP))
-			break;
-	if (i == POLL_COUNT)
-		err("wrcodec: codec cmd pending expired!");
-
-	cmd = (u32) addr & AC97C_INDEX_MASK;
-	cmd &= ~AC97C_READ;	// write command
-	cmd |= ((u32) data << AC97C_WD_BIT);	// OR in the data word
-	au_writel(cmd, AC97C_CMD);
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void waitcodec(struct ac97_codec *codec)
-{
-	u16             temp;
-	int             i;
-
-	/* codec_wait is used to wait for a ready state after
-	   an AC97C_RESET. */
-	au1000_delay(10);
-
-	// first poll the CODEC_READY tag bit
-	for (i = 0; i < POLL_COUNT; i++)
-		if (au_readl(AC97C_STATUS) & AC97C_READY)
-			break;
-	if (i == POLL_COUNT) {
-		err("waitcodec: CODEC_READY poll expired!");
-		return;
-	}
-	// get AC'97 powerdown control/status register
-	temp = rdcodec(codec, AC97_POWER_CONTROL);
-
-	// If anything is powered down, power'em up
-	if (temp & 0x7f00) {
-		// Power on
-		wrcodec(codec, AC97_POWER_CONTROL, 0);
-		au1000_delay(100);
-		// Reread
-		temp = rdcodec(codec, AC97_POWER_CONTROL);
-	}
-    
-	// Check if Codec REF,ANL,DAC,ADC ready
-	if ((temp & 0x7f0f) != 0x000f)
-		err("codec reg 26 status (0x%x) not ready!!", temp);
-}
-
-
-/* --------------------------------------------------------------------- */
-
-/* stop the ADC before calling */
-static void set_adc_rate(struct au1000_state *s, unsigned rate)
-{
-	struct dmabuf  *adc = &s->dma_adc;
-	struct dmabuf  *dac = &s->dma_dac;
-	unsigned        adc_rate, dac_rate;
-	u16             ac97_extstat;
-
-	if (s->no_vra) {
-		// calc SRC factor
-		adc->src_factor = ((96000 / rate) + 1) >> 1;
-		adc->sample_rate = 48000 / adc->src_factor;
-		return;
-	}
-
-	adc->src_factor = 1;
-
-	ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
-
-	rate = rate > 48000 ? 48000 : rate;
-
-	// enable VRA
-	wrcodec(&s->codec, AC97_EXTENDED_STATUS,
-		ac97_extstat | AC97_EXTSTAT_VRA);
-	// now write the sample rate
-	wrcodec(&s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
-	// read it back for actual supported rate
-	adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
-
-#ifdef AU1000_VERBOSE_DEBUG
-	dbg("%s: set to %d Hz", __FUNCTION__, adc_rate);
-#endif
-
-	// some codec's don't allow unequal DAC and ADC rates, in which case
-	// writing one rate reg actually changes both.
-	dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
-	if (dac->num_channels > 2)
-		wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
-	if (dac->num_channels > 4)
-		wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
-
-	adc->sample_rate = adc_rate;
-	dac->sample_rate = dac_rate;
-}
-
-/* stop the DAC before calling */
-static void set_dac_rate(struct au1000_state *s, unsigned rate)
-{
-	struct dmabuf  *dac = &s->dma_dac;
-	struct dmabuf  *adc = &s->dma_adc;
-	unsigned        adc_rate, dac_rate;
-	u16             ac97_extstat;
-
-	if (s->no_vra) {
-		// calc SRC factor
-		dac->src_factor = ((96000 / rate) + 1) >> 1;
-		dac->sample_rate = 48000 / dac->src_factor;
-		return;
-	}
-
-	dac->src_factor = 1;
-
-	ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
-
-	rate = rate > 48000 ? 48000 : rate;
-
-	// enable VRA
-	wrcodec(&s->codec, AC97_EXTENDED_STATUS,
-		ac97_extstat | AC97_EXTSTAT_VRA);
-	// now write the sample rate
-	wrcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
-	// I don't support different sample rates for multichannel,
-	// so make these channels the same.
-	if (dac->num_channels > 2)
-		wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
-	if (dac->num_channels > 4)
-		wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
-	// read it back for actual supported rate
-	dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
-
-#ifdef AU1000_VERBOSE_DEBUG
-	dbg("%s: set to %d Hz", __FUNCTION__, dac_rate);
-#endif
-
-	// some codec's don't allow unequal DAC and ADC rates, in which case
-	// writing one rate reg actually changes both.
-	adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
-
-	dac->sample_rate = dac_rate;
-	adc->sample_rate = adc_rate;
-}
-
-static void stop_dac(struct au1000_state *s)
-{
-	struct dmabuf  *db = &s->dma_dac;
-	unsigned long   flags;
-
-	if (db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	disable_dma(db->dmanr);
-
-	db->stopped = 1;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void  stop_adc(struct au1000_state *s)
-{
-	struct dmabuf  *db = &s->dma_adc;
-	unsigned long   flags;
-
-	if (db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	disable_dma(db->dmanr);
-
-	db->stopped = 1;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void set_xmit_slots(int num_channels)
-{
-	u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_XMIT_SLOTS_MASK;
-
-	switch (num_channels) {
-	case 1:		// mono
-	case 2:		// stereo, slots 3,4
-		ac97_config |= (0x3 << AC97C_XMIT_SLOTS_BIT);
-		break;
-	case 4:		// stereo with surround, slots 3,4,7,8
-		ac97_config |= (0x33 << AC97C_XMIT_SLOTS_BIT);
-		break;
-	case 6:		// stereo with surround and center/LFE, slots 3,4,6,7,8,9
-		ac97_config |= (0x7b << AC97C_XMIT_SLOTS_BIT);
-		break;
-	}
-
-	au_writel(ac97_config, AC97C_CONFIG);
-}
-
-static void     set_recv_slots(int num_channels)
-{
-	u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_RECV_SLOTS_MASK;
-
-	/*
-	 * Always enable slots 3 and 4 (stereo). Slot 6 is
-	 * optional Mic ADC, which I don't support yet.
-	 */
-	ac97_config |= (0x3 << AC97C_RECV_SLOTS_BIT);
-
-	au_writel(ac97_config, AC97C_CONFIG);
-}
-
-static void start_dac(struct au1000_state *s)
-{
-	struct dmabuf  *db = &s->dma_dac;
-	unsigned long   flags;
-	unsigned long   buf1, buf2;
-
-	if (!db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	au_readl(AC97C_STATUS);	// read status to clear sticky bits
-
-	// reset Buffer 1 and 2 pointers to nextOut and nextOut+dma_fragsize
-	buf1 = virt_to_phys(db->nextOut);
-	buf2 = buf1 + db->dma_fragsize;
-	if (buf2 >= db->dmaaddr + db->dmasize)
-		buf2 -= db->dmasize;
-
-	set_xmit_slots(db->num_channels);
-
-	init_dma(db->dmanr);
-	if (get_dma_active_buffer(db->dmanr) == 0) {
-		clear_dma_done0(db->dmanr);	// clear DMA done bit
-		set_dma_addr0(db->dmanr, buf1);
-		set_dma_addr1(db->dmanr, buf2);
-	} else {
-		clear_dma_done1(db->dmanr);	// clear DMA done bit
-		set_dma_addr1(db->dmanr, buf1);
-		set_dma_addr0(db->dmanr, buf2);
-	}
-	set_dma_count(db->dmanr, db->dma_fragsize>>1);
-	enable_dma_buffers(db->dmanr);
-
-	start_dma(db->dmanr);
-
-#ifdef AU1000_VERBOSE_DEBUG
-	dump_au1000_dma_channel(db->dmanr);
-#endif
-
-	db->stopped = 0;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct au1000_state *s)
-{
-	struct dmabuf  *db = &s->dma_adc;
-	unsigned long   flags;
-	unsigned long   buf1, buf2;
-
-	if (!db->stopped)
-		return;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	au_readl(AC97C_STATUS);	// read status to clear sticky bits
-
-	// reset Buffer 1 and 2 pointers to nextIn and nextIn+dma_fragsize
-	buf1 = virt_to_phys(db->nextIn);
-	buf2 = buf1 + db->dma_fragsize;
-	if (buf2 >= db->dmaaddr + db->dmasize)
-		buf2 -= db->dmasize;
-
-	set_recv_slots(db->num_channels);
-
-	init_dma(db->dmanr);
-	if (get_dma_active_buffer(db->dmanr) == 0) {
-		clear_dma_done0(db->dmanr);	// clear DMA done bit
-		set_dma_addr0(db->dmanr, buf1);
-		set_dma_addr1(db->dmanr, buf2);
-	} else {
-		clear_dma_done1(db->dmanr);	// clear DMA done bit
-		set_dma_addr1(db->dmanr, buf1);
-		set_dma_addr0(db->dmanr, buf2);
-	}
-	set_dma_count(db->dmanr, db->dma_fragsize>>1);
-	enable_dma_buffers(db->dmanr);
-
-	start_dma(db->dmanr);
-
-#ifdef AU1000_VERBOSE_DEBUG
-	dump_au1000_dma_channel(db->dmanr);
-#endif
-
-	db->stopped = 0;
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct au1000_state *s, struct dmabuf *db)
-{
-	struct page    *page, *pend;
-
-	if (db->rawbuf) {
-		/* undo marking the pages as reserved */
-		pend = virt_to_page(db->rawbuf +
-				    (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			ClearPageReserved(page);
-		dma_free_noncoherent(NULL,
-				PAGE_SIZE << db->buforder,
-				db->rawbuf,
-				db->dmaaddr);
-	}
-	db->rawbuf = db->nextIn = db->nextOut = NULL;
-	db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db)
-{
-	int             order;
-	unsigned user_bytes_per_sec;
-	unsigned        bufs;
-	struct page    *page, *pend;
-	unsigned        rate = db->sample_rate;
-
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-		for (order = DMABUF_DEFAULTORDER;
-		     order >= DMABUF_MINORDER; order--)
-			if ((db->rawbuf = dma_alloc_noncoherent(NULL,
-						PAGE_SIZE << order,
-						&db->dmaaddr,
-						0)))
-				break;
-		if (!db->rawbuf)
-			return -ENOMEM;
-		db->buforder = order;
-		/* now mark the pages as reserved;
-		   otherwise remap_pfn_range doesn't do what we want */
-		pend = virt_to_page(db->rawbuf +
-				    (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			SetPageReserved(page);
-	}
-
-	db->cnt_factor = 1;
-	if (db->sample_size == 8)
-		db->cnt_factor *= 2;
-	if (db->num_channels == 1)
-		db->cnt_factor *= 2;
-	db->cnt_factor *= db->src_factor;
-
-	db->count = 0;
-	db->nextIn = db->nextOut = db->rawbuf;
-
-	db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
-	db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
-					2 : db->num_channels);
-
-	user_bytes_per_sec = rate * db->user_bytes_per_sample;
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < user_bytes_per_sec)
-			db->fragshift = ld2(user_bytes_per_sec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(user_bytes_per_sec / 100 /
-				    (db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-
-	db->fragsize = 1 << db->fragshift;
-	db->dma_fragsize = db->fragsize * db->cnt_factor;
-	db->numfrag = bufs / db->dma_fragsize;
-
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->fragsize = 1 << db->fragshift;
-		db->dma_fragsize = db->fragsize * db->cnt_factor;
-		db->numfrag = bufs / db->dma_fragsize;
-	}
-
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-
-	db->dmasize = db->dma_fragsize * db->numfrag;
-	memset(db->rawbuf, 0, bufs);
-
-#ifdef AU1000_VERBOSE_DEBUG
-	dbg("rate=%d, samplesize=%d, channels=%d",
-	    rate, db->sample_size, db->num_channels);
-	dbg("fragsize=%d, cnt_factor=%d, dma_fragsize=%d",
-	    db->fragsize, db->cnt_factor, db->dma_fragsize);
-	dbg("numfrag=%d, dmasize=%d", db->numfrag, db->dmasize);
-#endif
-
-	db->ready = 1;
-	return 0;
-}
-
-static inline int prog_dmabuf_adc(struct au1000_state *s)
-{
-	stop_adc(s);
-	return prog_dmabuf(s, &s->dma_adc);
-
-}
-
-static inline int prog_dmabuf_dac(struct au1000_state *s)
-{
-	stop_dac(s);
-	return prog_dmabuf(s, &s->dma_dac);
-}
-
-
-/* hold spinlock for the following */
-static irqreturn_t dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct au1000_state *s = (struct au1000_state *) dev_id;
-	struct dmabuf  *dac = &s->dma_dac;
-	unsigned long   newptr;
-	u32 ac97c_stat, buff_done;
-
-	ac97c_stat = au_readl(AC97C_STATUS);
-#ifdef AU1000_VERBOSE_DEBUG
-	if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
-		dbg("AC97C status = 0x%08x", ac97c_stat);
-#endif
-
-	if ((buff_done = get_dma_buffer_done(dac->dmanr)) == 0) {
-		/* fastpath out, to ease interrupt sharing */
-		return IRQ_HANDLED;
-	}
-
-	spin_lock(&s->lock);
-	
-	if (buff_done != (DMA_D0 | DMA_D1)) {
-		dac->nextOut += dac->dma_fragsize;
-		if (dac->nextOut >= dac->rawbuf + dac->dmasize)
-			dac->nextOut -= dac->dmasize;
-
-		/* update playback pointers */
-		newptr = virt_to_phys(dac->nextOut) + dac->dma_fragsize;
-		if (newptr >= dac->dmaaddr + dac->dmasize)
-			newptr -= dac->dmasize;
-
-		dac->count -= dac->dma_fragsize;
-		dac->total_bytes += dac->dma_fragsize;
-
-		if (dac->count <= 0) {
-#ifdef AU1000_VERBOSE_DEBUG
-			dbg("dac underrun");
-#endif
-			spin_unlock(&s->lock);
-			stop_dac(s);
-			spin_lock(&s->lock);
-			dac->count = 0;
-			dac->nextIn = dac->nextOut;
-		} else if (buff_done == DMA_D0) {
-			clear_dma_done0(dac->dmanr);	// clear DMA done bit
-			set_dma_count0(dac->dmanr, dac->dma_fragsize>>1);
-			set_dma_addr0(dac->dmanr, newptr);
-			enable_dma_buffer0(dac->dmanr);	// reenable
-		} else {
-			clear_dma_done1(dac->dmanr);	// clear DMA done bit
-			set_dma_count1(dac->dmanr, dac->dma_fragsize>>1);
-			set_dma_addr1(dac->dmanr, newptr);
-			enable_dma_buffer1(dac->dmanr);	// reenable
-		}
-	} else {
-		// both done bits set, we missed an interrupt
-		spin_unlock(&s->lock);
-		stop_dac(s);
-		spin_lock(&s->lock);
-
-		dac->nextOut += 2*dac->dma_fragsize;
-		if (dac->nextOut >= dac->rawbuf + dac->dmasize)
-			dac->nextOut -= dac->dmasize;
-
-		dac->count -= 2*dac->dma_fragsize;
-		dac->total_bytes += 2*dac->dma_fragsize;
-
-		if (dac->count > 0) {
-			spin_unlock(&s->lock);
-			start_dac(s);
-			spin_lock(&s->lock);
-		}
-	}
-
-	/* wake up anybody listening */
-	if (waitqueue_active(&dac->wait))
-		wake_up(&dac->wait);
-
-	spin_unlock(&s->lock);
-
-	return IRQ_HANDLED;
-}
-
-
-static irqreturn_t adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct au1000_state *s = (struct au1000_state *) dev_id;
-	struct dmabuf  *adc = &s->dma_adc;
-	unsigned long   newptr;
-	u32 ac97c_stat, buff_done;
-
-	ac97c_stat = au_readl(AC97C_STATUS);
-#ifdef AU1000_VERBOSE_DEBUG
-	if (ac97c_stat & (AC97C_RU | AC97C_RO))
-		dbg("AC97C status = 0x%08x", ac97c_stat);
-#endif
-
-	if ((buff_done = get_dma_buffer_done(adc->dmanr)) == 0) {
-		/* fastpath out, to ease interrupt sharing */
-		return IRQ_HANDLED;
-	}
-
-	spin_lock(&s->lock);
-	
-	if (buff_done != (DMA_D0 | DMA_D1)) {
-		if (adc->count + adc->dma_fragsize > adc->dmasize) {
-			// Overrun. Stop ADC and log the error
-			spin_unlock(&s->lock);
-			stop_adc(s);
-			adc->error++;
-			err("adc overrun");
-			return IRQ_NONE;
-		}
-
-		adc->nextIn += adc->dma_fragsize;
-		if (adc->nextIn >= adc->rawbuf + adc->dmasize)
-			adc->nextIn -= adc->dmasize;
-
-		/* update capture pointers */
-		newptr = virt_to_phys(adc->nextIn) + adc->dma_fragsize;
-		if (newptr >= adc->dmaaddr + adc->dmasize)
-			newptr -= adc->dmasize;
-
-		adc->count += adc->dma_fragsize;
-		adc->total_bytes += adc->dma_fragsize;
-
-		if (buff_done == DMA_D0) {
-			clear_dma_done0(adc->dmanr);	// clear DMA done bit
-			set_dma_count0(adc->dmanr, adc->dma_fragsize>>1);
-			set_dma_addr0(adc->dmanr, newptr);
-			enable_dma_buffer0(adc->dmanr);	// reenable
-		} else {
-			clear_dma_done1(adc->dmanr);	// clear DMA done bit
-			set_dma_count1(adc->dmanr, adc->dma_fragsize>>1);
-			set_dma_addr1(adc->dmanr, newptr);
-			enable_dma_buffer1(adc->dmanr);	// reenable
-		}
-	} else {
-		// both done bits set, we missed an interrupt
-		spin_unlock(&s->lock);
-		stop_adc(s);
-		spin_lock(&s->lock);
-		
-		if (adc->count + 2*adc->dma_fragsize > adc->dmasize) {
-			// Overrun. Log the error
-			adc->error++;
-			err("adc overrun");
-			spin_unlock(&s->lock);
-			return IRQ_NONE;
-		}
-
-		adc->nextIn += 2*adc->dma_fragsize;
-		if (adc->nextIn >= adc->rawbuf + adc->dmasize)
-			adc->nextIn -= adc->dmasize;
-
-		adc->count += 2*adc->dma_fragsize;
-		adc->total_bytes += 2*adc->dma_fragsize;
-		
-		spin_unlock(&s->lock);
-		start_adc(s);
-		spin_lock(&s->lock);
-	}
-
-	/* wake up anybody listening */
-	if (waitqueue_active(&adc->wait))
-		wake_up(&adc->wait);
-
-	spin_unlock(&s->lock);
-
-	return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static loff_t au1000_llseek(struct file *file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
-
-static int au1000_open_mixdev(struct inode *inode, struct file *file)
-{
-	file->private_data = &au1000_state;
-	return nonseekable_open(inode, file);
-}
-
-static int au1000_release_mixdev(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
-                        unsigned long arg)
-{
-	return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static int au1000_ioctl_mixdev(struct inode *inode, struct file *file,
-			       unsigned int cmd, unsigned long arg)
-{
-	struct au1000_state *s = (struct au1000_state *)file->private_data;
-	struct ac97_codec *codec = &s->codec;
-
-	return mixdev_ioctl(codec, cmd, arg);
-}
-
-static /*const */ struct file_operations au1000_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= au1000_llseek,
-	.ioctl		= au1000_ioctl_mixdev,
-	.open		= au1000_open_mixdev,
-	.release	= au1000_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct au1000_state *s, int nonblock)
-{
-	unsigned long   flags;
-	int             count, tmo;
-
-	if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
-		return 0;
-
-	for (;;) {
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-			break;
-		if (nonblock)
-			return -EBUSY;
-		tmo = 1000 * count / (s->no_vra ?
-				      48000 : s->dma_dac.sample_rate);
-		tmo /= s->dma_dac.dma_bytes_per_sample;
-		au1000_delay(tmo);
-	}
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline u8 S16_TO_U8(s16 ch)
-{
-	return (u8) (ch >> 8) + 0x80;
-}
-static inline s16 U8_TO_S16(u8 ch)
-{
-	return (s16) (ch - 0x80) << 8;
-}
-
-/*
- * Translates user samples to dma buffer suitable for AC'97 DAC data:
- *     If mono, copy left channel to right channel in dma buffer.
- *     If 8 bit samples, cvt to 16-bit before writing to dma buffer.
- *     If interpolating (no VRA), duplicate every audio frame src_factor times.
- */
-static int translate_from_user(struct dmabuf *db,
-			       char* dmabuf,
-			       char* userbuf,
-			       int dmacount)
-{
-	int             sample, i;
-	int             interp_bytes_per_sample;
-	int             num_samples;
-	int             mono = (db->num_channels == 1);
-	char            usersample[12];
-	s16             ch, dmasample[6];
-
-	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-		// no translation necessary, just copy
-		if (copy_from_user(dmabuf, userbuf, dmacount))
-			return -EFAULT;
-		return dmacount;
-	}
-
-	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-	num_samples = dmacount / interp_bytes_per_sample;
-
-	for (sample = 0; sample < num_samples; sample++) {
-		if (copy_from_user(usersample, userbuf,
-				   db->user_bytes_per_sample)) {
-			dbg("%s: fault", __FUNCTION__);
-			return -EFAULT;
-		}
-
-		for (i = 0; i < db->num_channels; i++) {
-			if (db->sample_size == 8)
-				ch = U8_TO_S16(usersample[i]);
-			else
-				ch = *((s16 *) (&usersample[i * 2]));
-			dmasample[i] = ch;
-			if (mono)
-				dmasample[i + 1] = ch;	// right channel
-		}
-
-		// duplicate every audio frame src_factor times
-		for (i = 0; i < db->src_factor; i++)
-			memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
-
-		userbuf += db->user_bytes_per_sample;
-		dmabuf += interp_bytes_per_sample;
-	}
-
-	return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Translates AC'97 ADC samples to user buffer:
- *     If mono, send only left channel to user buffer.
- *     If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
- *     If decimating (no VRA), skip over src_factor audio frames.
- */
-static int translate_to_user(struct dmabuf *db,
-			     char* userbuf,
-			     char* dmabuf,
-			     int dmacount)
-{
-	int             sample, i;
-	int             interp_bytes_per_sample;
-	int             num_samples;
-	int             mono = (db->num_channels == 1);
-	char            usersample[12];
-
-	if (db->sample_size == 16 && !mono && db->src_factor == 1) {
-		// no translation necessary, just copy
-		if (copy_to_user(userbuf, dmabuf, dmacount))
-			return -EFAULT;
-		return dmacount;
-	}
-
-	interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
-	num_samples = dmacount / interp_bytes_per_sample;
-
-	for (sample = 0; sample < num_samples; sample++) {
-		for (i = 0; i < db->num_channels; i++) {
-			if (db->sample_size == 8)
-				usersample[i] =
-					S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
-			else
-				*((s16 *) (&usersample[i * 2])) =
-					*((s16 *) (&dmabuf[i * 2]));
-		}
-
-		if (copy_to_user(userbuf, usersample,
-				 db->user_bytes_per_sample)) {
-			dbg("%s: fault", __FUNCTION__);
-			return -EFAULT;
-		}
-
-		userbuf += db->user_bytes_per_sample;
-		dmabuf += interp_bytes_per_sample;
-	}
-
-	return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Copy audio data to/from user buffer from/to dma buffer, taking care
- * that we wrap when reading/writing the dma buffer. Returns actual byte
- * count written to or read from the dma buffer.
- */
-static int copy_dmabuf_user(struct dmabuf *db, char* userbuf,
-			    int count, int to_user)
-{
-	char           *bufptr = to_user ? db->nextOut : db->nextIn;
-	char           *bufend = db->rawbuf + db->dmasize;
-	int             cnt, ret;
-
-	if (bufptr + count > bufend) {
-		int             partial = (int) (bufend - bufptr);
-		if (to_user) {
-			if ((cnt = translate_to_user(db, userbuf,
-						     bufptr, partial)) < 0)
-				return cnt;
-			ret = cnt;
-			if ((cnt = translate_to_user(db, userbuf + partial,
-						     db->rawbuf,
-						     count - partial)) < 0)
-				return cnt;
-			ret += cnt;
-		} else {
-			if ((cnt = translate_from_user(db, bufptr, userbuf,
-						       partial)) < 0)
-				return cnt;
-			ret = cnt;
-			if ((cnt = translate_from_user(db, db->rawbuf,
-						       userbuf + partial,
-						       count - partial)) < 0)
-				return cnt;
-			ret += cnt;
-		}
-	} else {
-		if (to_user)
-			ret = translate_to_user(db, userbuf, bufptr, count);
-		else
-			ret = translate_from_user(db, bufptr, userbuf, count);
-	}
-
-	return ret;
-}
-
-
-static ssize_t au1000_read(struct file *file, char *buffer,
-			   size_t count, loff_t *ppos)
-{
-	struct au1000_state *s = (struct au1000_state *)file->private_data;
-	struct dmabuf  *db = &s->dma_adc;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t         ret;
-	unsigned long   flags;
-	int             cnt, usercnt, avail;
-
-	if (db->mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-
-	count *= db->cnt_factor;
-
-	mutex_lock(&s->sem);
-	add_wait_queue(&db->wait, &wait);
-
-	while (count > 0) {
-		// wait for samples in ADC dma buffer
-		do {
-			if (db->stopped)
-				start_adc(s);
-			spin_lock_irqsave(&s->lock, flags);
-			avail = db->count;
-			if (avail <= 0)
-				__set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (avail <= 0) {
-				if (file->f_flags & O_NONBLOCK) {
-					if (!ret)
-						ret = -EAGAIN;
-					goto out;
-				}
-				mutex_unlock(&s->sem);
-				schedule();
-				if (signal_pending(current)) {
-					if (!ret)
-						ret = -ERESTARTSYS;
-					goto out2;
-				}
-				mutex_lock(&s->sem);
-			}
-		} while (avail <= 0);
-
-		// copy from nextOut to user
-		if ((cnt = copy_dmabuf_user(db, buffer,
-					    count > avail ?
-					    avail : count, 1)) < 0) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-
-		spin_lock_irqsave(&s->lock, flags);
-		db->count -= cnt;
-		db->nextOut += cnt;
-		if (db->nextOut >= db->rawbuf + db->dmasize)
-			db->nextOut -= db->dmasize;
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		count -= cnt;
-		usercnt = cnt / db->cnt_factor;
-		buffer += usercnt;
-		ret += usercnt;
-	}			// while (count > 0)
-
-out:
-	mutex_unlock(&s->sem);
-out2:
-	remove_wait_queue(&db->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static ssize_t au1000_write(struct file *file, const char *buffer,
-	     		    size_t count, loff_t * ppos)
-{
-	struct au1000_state *s = (struct au1000_state *)file->private_data;
-	struct dmabuf  *db = &s->dma_dac;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t         ret = 0;
-	unsigned long   flags;
-	int             cnt, usercnt, avail;
-
-#ifdef AU1000_VERBOSE_DEBUG
-	dbg("write: count=%d", count);
-#endif
-
-	if (db->mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-
-	count *= db->cnt_factor;
-
-	mutex_lock(&s->sem);
-	add_wait_queue(&db->wait, &wait);
-
-	while (count > 0) {
-		// wait for space in playback buffer
-		do {
-			spin_lock_irqsave(&s->lock, flags);
-			avail = (int) db->dmasize - db->count;
-			if (avail <= 0)
-				__set_current_state(TASK_INTERRUPTIBLE);
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (avail <= 0) {
-				if (file->f_flags & O_NONBLOCK) {
-					if (!ret)
-						ret = -EAGAIN;
-					goto out;
-				}
-				mutex_unlock(&s->sem);
-				schedule();
-				if (signal_pending(current)) {
-					if (!ret)
-						ret = -ERESTARTSYS;
-					goto out2;
-				}
-				mutex_lock(&s->sem);
-			}
-		} while (avail <= 0);
-
-		// copy from user to nextIn
-		if ((cnt = copy_dmabuf_user(db, (char *) buffer,
-					    count > avail ?
-					    avail : count, 0)) < 0) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-
-		spin_lock_irqsave(&s->lock, flags);
-		db->count += cnt;
-		db->nextIn += cnt;
-		if (db->nextIn >= db->rawbuf + db->dmasize)
-			db->nextIn -= db->dmasize;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (db->stopped)
-			start_dac(s);
-
-		count -= cnt;
-		usercnt = cnt / db->cnt_factor;
-		buffer += usercnt;
-		ret += usercnt;
-	}			// while (count > 0)
-
-out:
-	mutex_unlock(&s->sem);
-out2:
-	remove_wait_queue(&db->wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int au1000_poll(struct file *file,
-				struct poll_table_struct *wait)
-{
-	struct au1000_state *s = (struct au1000_state *)file->private_data;
-	unsigned long   flags;
-	unsigned int    mask = 0;
-
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready)
-			return 0;
-		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready)
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-
-	spin_lock_irqsave(&s->lock, flags);
-	
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >=
-			    (signed)s->dma_dac.dma_fragsize) 
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed) s->dma_dac.dmasize >=
-			    s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int au1000_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct au1000_state *s = (struct au1000_state *)file->private_data;
-	struct dmabuf  *db;
-	unsigned long   size;
-	int ret = 0;
-
-	dbg("%s", __FUNCTION__);
-    
-	lock_kernel();
-	mutex_lock(&s->sem);
-	if (vma->vm_flags & VM_WRITE)
-		db = &s->dma_dac;
-	else if (vma->vm_flags & VM_READ)
-		db = &s->dma_adc;
-	else {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (vma->vm_pgoff != 0) {
-		ret = -EINVAL;
-		goto out;
-	}
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder)) {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(db->rawbuf),
-			     size, vma->vm_page_prot)) {
-		ret = -EAGAIN;
-		goto out;
-	}
-	vma->vm_flags &= ~VM_IO;
-	db->mapped = 1;
-out:
-	mutex_unlock(&s->sem);
-	unlock_kernel();
-	return ret;
-}
-
-
-#ifdef AU1000_VERBOSE_DEBUG
-static struct ioctl_str_t {
-	unsigned int    cmd;
-	const char     *str;
-} ioctl_str[] = {
-	{SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
-	{SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
-	{SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
-	{SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
-	{SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
-	{SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
-	{SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
-	{SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
-	{SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
-	{SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
-	{SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
-	{SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
-	{SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
-	{SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
-	{SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
-	{SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
-	{SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
-	{SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
-	{SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
-	{SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
-	{SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
-	{SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
-	{SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
-	{SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
-	{SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
-	{SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
-	{SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
-	{SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
-	{SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
-	{OSS_GETVERSION, "OSS_GETVERSION"},
-	{SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
-	{SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
-	{SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
-	{SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
-};
-#endif
-
-// Need to hold a spin-lock before calling this!
-static int dma_count_done(struct dmabuf *db)
-{
-	if (db->stopped)
-		return 0;
-
-	return db->dma_fragsize - get_dma_residue(db->dmanr);
-}
-
-
-static int au1000_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-	struct au1000_state *s = (struct au1000_state *)file->private_data;
-	unsigned long   flags;
-	audio_buf_info  abinfo;
-	count_info      cinfo;
-	int             count;
-	int             val, mapped, ret, diff;
-
-	mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-#ifdef AU1000_VERBOSE_DEBUG
-	for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
-		if (ioctl_str[count].cmd == cmd)
-			break;
-	}
-	if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))
-		dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg);
-	else
-		dbg("ioctl 0x%x unknown, arg=0x%lx", cmd, arg);
-#endif
-
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, (int *) arg);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, file->f_flags & O_NONBLOCK);
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
-				DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
-
-	case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq();
-			s->dma_dac.count = s->dma_dac.total_bytes = 0;
-			s->dma_dac.nextIn = s->dma_dac.nextOut =
-				s->dma_dac.rawbuf;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq();
-			s->dma_adc.count = s->dma_adc.total_bytes = 0;
-			s->dma_adc.nextIn = s->dma_adc.nextOut =
-				s->dma_adc.rawbuf;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val >= 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				set_adc_rate(s, val);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				set_dac_rate(s, val);
-			}
-			if (s->open_mode & FMODE_READ)
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			if (s->open_mode & FMODE_WRITE)
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-		}
-		return put_user((file->f_mode & FMODE_READ) ?
-				s->dma_adc.sample_rate :
-				s->dma_dac.sample_rate,
-				(int *)arg);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.num_channels = val ? 2 : 1;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.num_channels = val ? 2 : 1;
-			if (s->codec_ext_caps & AC97_EXT_DACS) {
-				// disable surround and center/lfe in AC'97
-				u16 ext_stat = rdcodec(&s->codec,
-						       AC97_EXTENDED_STATUS);
-				wrcodec(&s->codec, AC97_EXTENDED_STATUS,
-					ext_stat | (AC97_EXTSTAT_PRI |
-						    AC97_EXTSTAT_PRJ |
-						    AC97_EXTSTAT_PRK));
-			}
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != 0) {
-			if (file->f_mode & FMODE_READ) {
-				if (val < 0 || val > 2)
-					return -EINVAL;
-				stop_adc(s);
-				s->dma_adc.num_channels = val;
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				switch (val) {
-				case 1:
-				case 2:
-					break;
-				case 3:
-				case 5:
-					return -EINVAL;
-				case 4:
-					if (!(s->codec_ext_caps &
-					      AC97_EXTID_SDAC))
-						return -EINVAL;
-					break;
-				case 6:
-					if ((s->codec_ext_caps &
-					     AC97_EXT_DACS) != AC97_EXT_DACS)
-						return -EINVAL;
-					break;
-				default:
-					return -EINVAL;
-				}
-
-				stop_dac(s);
-				if (val <= 2 &&
-				    (s->codec_ext_caps & AC97_EXT_DACS)) {
-					// disable surround and center/lfe
-					// channels in AC'97
-					u16             ext_stat =
-						rdcodec(&s->codec,
-							AC97_EXTENDED_STATUS);
-					wrcodec(&s->codec,
-						AC97_EXTENDED_STATUS,
-						ext_stat | (AC97_EXTSTAT_PRI |
-							    AC97_EXTSTAT_PRJ |
-							    AC97_EXTSTAT_PRK));
-				} else if (val >= 4) {
-					// enable surround, center/lfe
-					// channels in AC'97
-					u16             ext_stat =
-						rdcodec(&s->codec,
-							AC97_EXTENDED_STATUS);
-					ext_stat &= ~AC97_EXTSTAT_PRJ;
-					if (val == 6)
-						ext_stat &=
-							~(AC97_EXTSTAT_PRI |
-							  AC97_EXTSTAT_PRK);
-					wrcodec(&s->codec,
-						AC97_EXTENDED_STATUS,
-						ext_stat);
-				}
-
-				s->dma_dac.num_channels = val;
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-			}
-		}
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_GETFMTS:	/* Returns a mask */
-		return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
-
-	case SNDCTL_DSP_SETFMT:	/* Selects ONE fmt */
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				if (val == AFMT_S16_LE)
-					s->dma_adc.sample_size = 16;
-				else {
-					val = AFMT_U8;
-					s->dma_adc.sample_size = 8;
-				}
-				if ((ret = prog_dmabuf_adc(s)))
-					return ret;
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				if (val == AFMT_S16_LE)
-					s->dma_dac.sample_size = 16;
-				else {
-					val = AFMT_U8;
-					s->dma_dac.sample_size = 8;
-				}
-				if ((ret = prog_dmabuf_dac(s)))
-					return ret;
-			}
-		} else {
-			if (file->f_mode & FMODE_READ)
-				val = (s->dma_adc.sample_size == 16) ?
-					AFMT_S16_LE : AFMT_U8;
-			else
-				val = (s->dma_dac.sample_size == 16) ?
-					AFMT_S16_LE : AFMT_U8;
-		}
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_POST:
-		return 0;
-
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		spin_lock_irqsave(&s->lock, flags);
-		if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
-			val |= PCM_ENABLE_OUTPUT;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, (int *) arg);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT)
-				start_adc(s);
-			else
-				stop_adc(s);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT)
-				start_dac(s);
-			else
-				stop_dac(s);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		abinfo.fragsize = s->dma_dac.fragsize;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		count -= dma_count_done(&s->dma_dac);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		abinfo.bytes = (s->dma_dac.dmasize - count) /
-			s->dma_dac.cnt_factor;
-		abinfo.fragstotal = s->dma_dac.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
-#ifdef AU1000_VERBOSE_DEBUG
-		dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);
-#endif
-		return copy_to_user((void *) arg, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		abinfo.fragsize = s->dma_adc.fragsize;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_adc.count;
-		count += dma_count_done(&s->dma_adc);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		abinfo.bytes = count / s->dma_adc.cnt_factor;
-		abinfo.fragstotal = s->dma_adc.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
-		return copy_to_user((void *) arg, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_NONBLOCK:
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		count -= dma_count_done(&s->dma_dac);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		count /= s->dma_dac.cnt_factor;
-		return put_user(count, (int *) arg);
-
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cinfo.bytes = s->dma_adc.total_bytes;
-		count = s->dma_adc.count;
-		if (!s->dma_adc.stopped) {
-			diff = dma_count_done(&s->dma_adc);
-			count += diff;
-			cinfo.bytes += diff;
-			cinfo.ptr =  virt_to_phys(s->dma_adc.nextIn) + diff -
-				s->dma_adc.dmaaddr;
-		} else
-			cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
-				s->dma_adc.dmaaddr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		cinfo.blocks = count >> s->dma_adc.fragshift;
-		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cinfo.bytes = s->dma_dac.total_bytes;
-		count = s->dma_dac.count;
-		if (!s->dma_dac.stopped) {
-			diff = dma_count_done(&s->dma_dac);
-			count -= diff;
-			cinfo.bytes += diff;
-			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
-				s->dma_dac.dmaaddr;
-		} else
-			cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
-				s->dma_dac.dmaaddr;
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		cinfo.blocks = count >> s->dma_dac.fragshift;
-		return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE)
-			return put_user(s->dma_dac.fragsize, (int *) arg);
-		else
-			return put_user(s->dma_adc.fragsize, (int *) arg);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-			return -EINVAL;
-		if (get_user(val, (int *) arg))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.subdivision = val;
-			if ((ret = prog_dmabuf_adc(s)))
-				return ret;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.subdivision = val;
-			if ((ret = prog_dmabuf_dac(s)))
-				return ret;
-		}
-		return 0;
-
-	case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ?
-				s->dma_adc.sample_rate :
-				s->dma_dac.sample_rate,
-				(int *)arg);
-
-	case SOUND_PCM_READ_CHANNELS:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->dma_adc.num_channels, (int *)arg);
-		else
-			return put_user(s->dma_dac.num_channels, (int *)arg);
-
-	case SOUND_PCM_READ_BITS:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->dma_adc.sample_size, (int *)arg);
-		else
-			return put_user(s->dma_dac.sample_size, (int *)arg);
-
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_READ_FILTER:
-		return -EINVAL;
-	}
-
-	return mixdev_ioctl(&s->codec, cmd, arg);
-}
-
-
-static int  au1000_open(struct inode *inode, struct file *file)
-{
-	int             minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct au1000_state *s = &au1000_state;
-	int             ret;
-
-#ifdef AU1000_VERBOSE_DEBUG
-	if (file->f_flags & O_NONBLOCK)
-		dbg("%s: non-blocking", __FUNCTION__);
-	else
-		dbg("%s: blocking", __FUNCTION__);
-#endif
-	
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & file->f_mode) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-
-	stop_dac(s);
-	stop_adc(s);
-
-	if (file->f_mode & FMODE_READ) {
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
-			s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
-		s->dma_adc.num_channels = 1;
-		s->dma_adc.sample_size = 8;
-		set_adc_rate(s, 8000);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->dma_adc.sample_size = 16;
-	}
-
-	if (file->f_mode & FMODE_WRITE) {
-		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
-			s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
-		s->dma_dac.num_channels = 1;
-		s->dma_dac.sample_size = 8;
-		set_dac_rate(s, 8000);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->dma_dac.sample_size = 16;
-	}
-
-	if (file->f_mode & FMODE_READ) {
-		if ((ret = prog_dmabuf_adc(s)))
-			return ret;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if ((ret = prog_dmabuf_dac(s)))
-			return ret;
-	}
-
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_unlock(&s->open_mutex);
-	mutex_init(&s->sem);
-	return nonseekable_open(inode, file);
-}
-
-static int au1000_release(struct inode *inode, struct file *file)
-{
-	struct au1000_state *s = (struct au1000_state *)file->private_data;
-
-	lock_kernel();
-	
-	if (file->f_mode & FMODE_WRITE) {
-		unlock_kernel();
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-		lock_kernel();
-	}
-
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac(s);
-		dealloc_dmabuf(s, &s->dma_dac);
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-		dealloc_dmabuf(s, &s->dma_adc);
-	}
-	s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
-	mutex_unlock(&s->open_mutex);
-	wake_up(&s->open_wait);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const */ struct file_operations au1000_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= au1000_llseek,
-	.read		= au1000_read,
-	.write		= au1000_write,
-	.poll		= au1000_poll,
-	.ioctl		= au1000_ioctl,
-	.mmap		= au1000_mmap,
-	.open		= au1000_open,
-	.release	= au1000_release,
-};
-
-
-/* --------------------------------------------------------------------- */
-
-
-/* --------------------------------------------------------------------- */
-
-/*
- * for debugging purposes, we'll create a proc device that dumps the
- * CODEC chipstate
- */
-
-#ifdef AU1000_DEBUG
-static int proc_au1000_dump(char *buf, char **start, off_t fpos,
-			    int length, int *eof, void *data)
-{
-	struct au1000_state *s = &au1000_state;
-	int             cnt, len = 0;
-
-	/* print out header */
-	len += sprintf(buf + len, "\n\t\tAU1000 Audio Debug\n\n");
-
-	// print out digital controller state
-	len += sprintf(buf + len, "AU1000 Audio Controller registers\n");
-	len += sprintf(buf + len, "---------------------------------\n");
-	len += sprintf (buf + len, "AC97C_CONFIG = %08x\n",
-			au_readl(AC97C_CONFIG));
-	len += sprintf (buf + len, "AC97C_STATUS = %08x\n",
-			au_readl(AC97C_STATUS));
-	len += sprintf (buf + len, "AC97C_CNTRL  = %08x\n",
-			au_readl(AC97C_CNTRL));
-
-	/* print out CODEC state */
-	len += sprintf(buf + len, "\nAC97 CODEC registers\n");
-	len += sprintf(buf + len, "----------------------\n");
-	for (cnt = 0; cnt <= 0x7e; cnt += 2)
-		len += sprintf(buf + len, "reg %02x = %04x\n",
-			       cnt, rdcodec(&s->codec, cnt));
-
-	if (fpos >= len) {
-		*start = buf;
-		*eof = 1;
-		return 0;
-	}
-	*start = buf + fpos;
-	if ((len -= fpos) > length)
-		return length;
-	*eof = 1;
-	return len;
-
-}
-#endif /* AU1000_DEBUG */
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com");
-MODULE_DESCRIPTION("Au1000 Audio Driver");
-
-/* --------------------------------------------------------------------- */
-
-static int __devinit au1000_probe(void)
-{
-	struct au1000_state *s = &au1000_state;
-	int             val;
-#ifdef AU1000_DEBUG
-	char            proc_str[80];
-#endif
-
-	memset(s, 0, sizeof(struct au1000_state));
-
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac.wait);
-	init_waitqueue_head(&s->open_wait);
-	mutex_init(&s->open_mutex);
-	spin_lock_init(&s->lock);
-	s->codec.private_data = s;
-	s->codec.id = 0;
-	s->codec.codec_read = rdcodec;
-	s->codec.codec_write = wrcodec;
-	s->codec.codec_wait = waitcodec;
-
-	if (!request_mem_region(CPHYSADDR(AC97C_CONFIG),
-			    0x14, AU1000_MODULE_NAME)) {
-		err("AC'97 ports in use");
-		return -1;
-	}
-	// Allocate the DMA Channels
-	if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX,
-						   "audio DAC",
-						   dac_dma_interrupt,
-						   IRQF_DISABLED, s)) < 0) {
-		err("Can't get DAC DMA");
-		goto err_dma1;
-	}
-	if ((s->dma_adc.dmanr = request_au1000_dma(DMA_ID_AC97C_RX,
-						   "audio ADC",
-						   adc_dma_interrupt,
-						   IRQF_DISABLED, s)) < 0) {
-		err("Can't get ADC DMA");
-		goto err_dma2;
-	}
-
-	info("DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d",
-	     s->dma_dac.dmanr, get_dma_done_irq(s->dma_dac.dmanr),
-	     s->dma_adc.dmanr, get_dma_done_irq(s->dma_adc.dmanr));
-
-	// enable DMA coherency in read/write DMA channels
-	set_dma_mode(s->dma_dac.dmanr,
-		     get_dma_mode(s->dma_dac.dmanr) & ~DMA_NC);
-	set_dma_mode(s->dma_adc.dmanr,
-		     get_dma_mode(s->dma_adc.dmanr) & ~DMA_NC);
-
-	/* register devices */
-
-	if ((s->dev_audio = register_sound_dsp(&au1000_audio_fops, -1)) < 0)
-		goto err_dev1;
-	if ((s->codec.dev_mixer =
-	     register_sound_mixer(&au1000_mixer_fops, -1)) < 0)
-		goto err_dev2;
-
-#ifdef AU1000_DEBUG
-	/* intialize the debug proc device */
-	s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL,
-				       proc_au1000_dump, NULL);
-#endif /* AU1000_DEBUG */
-
-	// configure pins for AC'97
-	au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
-
-	// Assert reset for 10msec to the AC'97 controller, and enable clock
-	au_writel(AC97C_RS | AC97C_CE, AC97C_CNTRL);
-	au1000_delay(10);
-	au_writel(AC97C_CE, AC97C_CNTRL);
-	au1000_delay(10);	// wait for clock to stabilize
-
-	/* cold reset the AC'97 */
-	au_writel(AC97C_RESET, AC97C_CONFIG);
-	au1000_delay(10);
-	au_writel(0, AC97C_CONFIG);
-	/* need to delay around 500msec(bleech) to give
-	   some CODECs enough time to wakeup */
-	au1000_delay(500);
-
-	/* warm reset the AC'97 to start the bitclk */
-	au_writel(AC97C_SG | AC97C_SYNC, AC97C_CONFIG);
-	udelay(100);
-	au_writel(0, AC97C_CONFIG);
-
-	/* codec init */
-	if (!ac97_probe_codec(&s->codec))
-		goto err_dev3;
-
-	s->codec_base_caps = rdcodec(&s->codec, AC97_RESET);
-	s->codec_ext_caps = rdcodec(&s->codec, AC97_EXTENDED_ID);
-	info("AC'97 Base/Extended ID = %04x/%04x",
-	     s->codec_base_caps, s->codec_ext_caps);
-
-	/*
-	 * On the Pb1000, audio playback is on the AUX_OUT
-	 * channel (which defaults to LNLVL_OUT in AC'97
-	 * rev 2.2) so make sure this channel is listed
-	 * as supported (soundcard.h calls this channel
-	 * ALTPCM). ac97_codec.c does not handle detection
-	 * of this channel correctly.
-	 */
-	s->codec.supported_mixers |= SOUND_MASK_ALTPCM;
-	/*
-	 * Now set AUX_OUT's default volume.
-	 */
-	val = 0x4343;
-	mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_ALTPCM,
-		     (unsigned long) &val);
-	
-	if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
-		// codec does not support VRA
-		s->no_vra = 1;
-	} else if (!vra) {
-		// Boot option says disable VRA
-		u16 ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
-		wrcodec(&s->codec, AC97_EXTENDED_STATUS,
-			ac97_extstat & ~AC97_EXTSTAT_VRA);
-		s->no_vra = 1;
-	}
-	if (s->no_vra)
-		info("no VRA, interpolating and decimating");
-
-	/* set mic to be the recording source */
-	val = SOUND_MASK_MIC;
-	mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC,
-		     (unsigned long) &val);
-
-#ifdef AU1000_DEBUG
-	sprintf(proc_str, "driver/%s/%d/ac97", AU1000_MODULE_NAME,
-		s->codec.id);
-	s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,
-					     ac97_read_proc, &s->codec);
-#endif
-
-#ifdef CONFIG_MIPS_XXS1500
-	/* deassert eapd */
-	wrcodec(&s->codec, AC97_POWER_CONTROL,
-			rdcodec(&s->codec, AC97_POWER_CONTROL) & ~0x8000);
-	/* mute a number of signals which seem to be causing problems
-	 * if not muted.
-	 */
-	wrcodec(&s->codec, AC97_PCBEEP_VOL, 0x8000);
-	wrcodec(&s->codec, AC97_PHONE_VOL, 0x8008);
-	wrcodec(&s->codec, AC97_MIC_VOL, 0x8008);
-	wrcodec(&s->codec, AC97_LINEIN_VOL, 0x8808);
-	wrcodec(&s->codec, AC97_CD_VOL, 0x8808);
-	wrcodec(&s->codec, AC97_VIDEO_VOL, 0x8808);
-	wrcodec(&s->codec, AC97_AUX_VOL, 0x8808);
-	wrcodec(&s->codec, AC97_PCMOUT_VOL, 0x0808);
-	wrcodec(&s->codec, AC97_GENERAL_PURPOSE, 0x2000);
-#endif
-
-	return 0;
-
- err_dev3:
-	unregister_sound_mixer(s->codec.dev_mixer);
- err_dev2:
-	unregister_sound_dsp(s->dev_audio);
- err_dev1:
-	free_au1000_dma(s->dma_adc.dmanr);
- err_dma2:
-	free_au1000_dma(s->dma_dac.dmanr);
- err_dma1:
-	release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
-	return -1;
-}
-
-static void au1000_remove(void)
-{
-	struct au1000_state *s = &au1000_state;
-
-	if (!s)
-		return;
-#ifdef AU1000_DEBUG
-	if (s->ps)
-		remove_proc_entry(AU1000_MODULE_NAME, NULL);
-#endif /* AU1000_DEBUG */
-	synchronize_irq();
-	free_au1000_dma(s->dma_adc.dmanr);
-	free_au1000_dma(s->dma_dac.dmanr);
-	release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->codec.dev_mixer);
-}
-
-static int __init init_au1000(void)
-{
-	info("stevel@mvista.com, built " __TIME__ " on " __DATE__);
-	return au1000_probe();
-}
-
-static void __exit cleanup_au1000(void)
-{
-	info("unloading");
-	au1000_remove();
-}
-
-module_init(init_au1000);
-module_exit(cleanup_au1000);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-static int __init au1000_setup(char *options)
-{
-	char           *this_opt;
-
-	if (!options || !*options)
-		return 0;
-
-	while ((this_opt = strsep(&options, ","))) {
-		if (!*this_opt)
-			continue;
-		if (!strncmp(this_opt, "vra", 3)) {
-			vra = 1;
-		}
-	}
-
-	return 1;
-}
-
-__setup("au1000_audio=", au1000_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/audio_syms.c b/sound/oss/audio_syms.c
deleted file mode 100644
index 5da217f..0000000
--- a/sound/oss/audio_syms.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Exported symbols for audio driver.
- */
-
-#include <linux/module.h>
-
-char audio_syms_symbol;
-
-#include "sound_config.h"
-#include "sound_calls.h"
-
-EXPORT_SYMBOL(DMAbuf_start_dma);
-EXPORT_SYMBOL(DMAbuf_open_dma);
-EXPORT_SYMBOL(DMAbuf_close_dma);
-EXPORT_SYMBOL(DMAbuf_inputintr);
-EXPORT_SYMBOL(DMAbuf_outputintr);
diff --git a/sound/oss/awe_hw.h b/sound/oss/awe_hw.h
deleted file mode 100644
index ab00c3c..0000000
--- a/sound/oss/awe_hw.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * sound/oss/awe_hw.h
- *
- * Access routines and definitions for the low level driver for the 
- * Creative AWE32/SB32/AWE64 wave table synth.
- *   version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-2000 Takashi Iwai
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_HW_H_DEF
-#define AWE_HW_H_DEF
-
-/*
- * Emu-8000 control registers
- * name(channel)	reg, port
- */
-
-#define awe_cmd_idx(reg,ch)	(((reg)<< 5) | (ch))
-
-#define Data0    0		/* 0x620: doubleword r/w */
-#define Data1    1		/* 0xA20: doubleword r/w */
-#define Data2    2		/* 0xA22: word r/w */
-#define Data3    3		/* 0xE20: word r/w */
-#define Pointer  4		/* 0xE22 register pointer r/w */
-
-#define AWE_CPF(ch)	awe_cmd_idx(0,ch), Data0	/* DW: current pitch and fractional address */
-#define AWE_PTRX(ch)	awe_cmd_idx(1,ch), Data0	/* DW: pitch target and reverb send */
-#define AWE_CVCF(ch)	awe_cmd_idx(2,ch), Data0	/* DW: current volume and filter cutoff */
-#define AWE_VTFT(ch)	awe_cmd_idx(3,ch), Data0	/* DW: volume and filter cutoff targets */
-#define AWE_0080(ch)	awe_cmd_idx(4,ch), Data0	/* DW: ?? */
-#define AWE_00A0(ch)	awe_cmd_idx(5,ch), Data0	/* DW: ?? */
-#define AWE_PSST(ch)	awe_cmd_idx(6,ch), Data0	/* DW: pan send and loop start address */
-#define AWE_CSL(ch)	awe_cmd_idx(7,ch), Data0	/* DW: chorus send and loop end address */
-#define AWE_CCCA(ch)	awe_cmd_idx(0,ch), Data1	/* DW: Q, control bits, and current address */
-#define AWE_HWCF4	awe_cmd_idx(1,9),  Data1	/* DW: config dw 4 */
-#define AWE_HWCF5	awe_cmd_idx(1,10), Data1	/* DW: config dw 5 */
-#define AWE_HWCF6	awe_cmd_idx(1,13), Data1	/* DW: config dw 6 */
-#define AWE_HWCF7	awe_cmd_idx(1,14), Data1	/* DW: config dw 7? (not documented) */
-#define AWE_SMALR	awe_cmd_idx(1,20), Data1	/* DW: sound memory address for left read */
-#define AWE_SMARR	awe_cmd_idx(1,21), Data1	/* DW:    for right read */
-#define AWE_SMALW	awe_cmd_idx(1,22), Data1	/* DW: sound memory address for left write */
-#define AWE_SMARW	awe_cmd_idx(1,23), Data1	/* DW:    for right write */
-#define AWE_SMLD	awe_cmd_idx(1,26), Data1	/* W: sound memory left data */
-#define AWE_SMRD	awe_cmd_idx(1,26), Data2	/* W:    right data */
-#define AWE_WC		awe_cmd_idx(1,27), Data2	/* W: sample counter */
-#define AWE_WC_Cmd	awe_cmd_idx(1,27)
-#define AWE_WC_Port	Data2
-#define AWE_HWCF1	awe_cmd_idx(1,29), Data1	/* W: config w 1 */
-#define AWE_HWCF2	awe_cmd_idx(1,30), Data1	/* W: config w 2 */
-#define AWE_HWCF3	awe_cmd_idx(1,31), Data1	/* W: config w 3 */
-#define AWE_INIT1(ch)	awe_cmd_idx(2,ch), Data1	/* W: init array 1 */
-#define AWE_INIT2(ch)	awe_cmd_idx(2,ch), Data2	/* W: init array 2 */
-#define AWE_INIT3(ch)	awe_cmd_idx(3,ch), Data1	/* W: init array 3 */
-#define AWE_INIT4(ch)	awe_cmd_idx(3,ch), Data2	/* W: init array 4 */
-#define AWE_ENVVOL(ch)	awe_cmd_idx(4,ch), Data1	/* W: volume envelope delay */
-#define AWE_DCYSUSV(ch)	awe_cmd_idx(5,ch), Data1	/* W: volume envelope sustain and decay */
-#define AWE_ENVVAL(ch)	awe_cmd_idx(6,ch), Data1	/* W: modulation envelope delay */
-#define AWE_DCYSUS(ch)	awe_cmd_idx(7,ch), Data1	/* W: modulation envelope sustain and decay */
-#define AWE_ATKHLDV(ch)	awe_cmd_idx(4,ch), Data2	/* W: volume envelope attack and hold */
-#define AWE_LFO1VAL(ch)	awe_cmd_idx(5,ch), Data2	/* W: LFO#1 Delay */
-#define AWE_ATKHLD(ch)	awe_cmd_idx(6,ch), Data2	/* W: modulation envelope attack and hold */
-#define AWE_LFO2VAL(ch)	awe_cmd_idx(7,ch), Data2	/* W: LFO#2 Delay */
-#define AWE_IP(ch)	awe_cmd_idx(0,ch), Data3	/* W: initial pitch */
-#define AWE_IFATN(ch)	awe_cmd_idx(1,ch), Data3	/* W: initial filter cutoff and attenuation */
-#define AWE_PEFE(ch)	awe_cmd_idx(2,ch), Data3	/* W: pitch and filter envelope heights */
-#define AWE_FMMOD(ch)	awe_cmd_idx(3,ch), Data3	/* W: vibrato and filter modulation freq */
-#define AWE_TREMFRQ(ch)	awe_cmd_idx(4,ch), Data3	/* W: LFO#1 tremolo amount and freq */
-#define AWE_FM2FRQ2(ch)	awe_cmd_idx(5,ch), Data3	/* W: LFO#2 vibrato amount and freq */
-
-/* used during detection (returns ROM version?; not documented in ADIP) */
-#define AWE_U1		0xE0, Data3	  /* (R)(W) used in initialization */
-#define AWE_U2(ch)	0xC0+(ch), Data3  /* (W)(W) used in init envelope  */
-
-
-#define AWE_MAX_VOICES		32
-#define AWE_NORMAL_VOICES	30	/*30&31 are reserved for DRAM refresh*/
-
-#define AWE_MAX_CHANNELS	32	/* max midi channels (must >= voices) */
-#define AWE_MAX_LAYERS	AWE_MAX_VOICES	/* maximum number of multiple layers */
-
-#define AWE_DRAM_OFFSET		0x200000
-#define AWE_MAX_DRAM_SIZE	(28 * 1024)	/* 28 MB is max onboard memory */
-
-#endif
diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c
deleted file mode 100644
index 01c592c..0000000
--- a/sound/oss/awe_wave.c
+++ /dev/null
@@ -1,6149 +0,0 @@
-/*
- * sound/oss/awe_wave.c
- *
- * The low level driver for the AWE32/SB32/AWE64 wave table synth.
- *   version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-2000 Takashi Iwai
- *
- * 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.
- */
-
-/*
- * Changelog:
- * Aug 18, 2003, Adam Belay <ambx1@neo.rr.com>
- * - detection code rewrite
- */
-
-#include <linux/awe_voice.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/pnp.h>
-
-#include "sound_config.h"
-
-#include "awe_wave.h"
-#include "awe_hw.h"
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-#include "tuning.h"
-#include <linux/ultrasound.h>
-#endif
-
-/*
- * debug message
- */
-
-#ifdef AWE_DEBUG_ON
-#define DEBUG(LVL,XXX)	{if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
-#define ERRMSG(XXX)	{if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
-#define FATALERR(XXX)	XXX
-#else
-#define DEBUG(LVL,XXX) /**/
-#define ERRMSG(XXX)	XXX
-#define FATALERR(XXX)	XXX
-#endif
-
-/*
- * bank and voice record
- */
-
-typedef struct _sf_list sf_list;
-typedef struct _awe_voice_list awe_voice_list;
-typedef struct _awe_sample_list awe_sample_list;
-
-/* soundfont record */
-struct _sf_list {
-	unsigned short sf_id;	/* id number */
-	unsigned short type;	/* lock & shared flags */
-	int num_info;		/* current info table index */
-	int num_sample;		/* current sample table index */
-	int mem_ptr;		/* current word byte pointer */
-	awe_voice_list *infos, *last_infos;	/* instruments */
-	awe_sample_list *samples, *last_samples;	/* samples */
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-	sf_list *shared;	/* shared list */
-	unsigned char name[AWE_PATCH_NAME_LEN];	/* sharing id */
-#endif
-	sf_list *next, *prev;
-};
-
-/* instrument list */
-struct _awe_voice_list {
-	awe_voice_info v;	/* instrument information */
-	sf_list *holder;	/* parent sf_list of this record */
-	unsigned char bank, instr;	/* preset number information */
-	char type, disabled;	/* type=normal/mapped, disabled=boolean */
-	awe_voice_list *next;	/* linked list with same sf_id */
-	awe_voice_list *next_instr;	/* instrument list */
-	awe_voice_list *next_bank;	/* hash table list */
-};
-
-/* voice list type */
-#define V_ST_NORMAL	0
-#define V_ST_MAPPED	1
-
-/* sample list */
-struct _awe_sample_list {
-	awe_sample_info v;	/* sample information */
-	sf_list *holder;	/* parent sf_list of this record */
-	awe_sample_list *next;	/* linked list with same sf_id */
-};
-
-/* sample and information table */
-static int current_sf_id;	/* current number of fonts */
-static int locked_sf_id;	/* locked position */
-static sf_list *sfhead, *sftail;	/* linked-lists */
-
-#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0)
-#define awe_free_info() (sftail ? sftail->num_info : 0)
-#define awe_free_sample() (sftail ? sftail->num_sample : 0)
-
-#define AWE_MAX_PRESETS		256
-#define AWE_DEFAULT_PRESET	0
-#define AWE_DEFAULT_BANK	0
-#define AWE_DEFAULT_DRUM	0
-#define AWE_DRUM_BANK		128
-
-#define MAX_LAYERS	AWE_MAX_VOICES
-
-/* preset table index */
-static awe_voice_list *preset_table[AWE_MAX_PRESETS];
-
-/*
- * voice table
- */
-
-/* effects table */
-typedef	struct FX_Rec { /* channel effects */
-	unsigned char flags[AWE_FX_END];
-	short val[AWE_FX_END];
-} FX_Rec;
-
-
-/* channel parameters */
-typedef struct _awe_chan_info {
-	int channel;		/* channel number */
-	int bank;		/* current tone bank */
-	int instr;		/* current program */
-	int bender;		/* midi pitchbend (-8192 - 8192) */
-	int bender_range;	/* midi bender range (x100) */
-	int panning;		/* panning (0-127) */
-	int main_vol;		/* channel volume (0-127) */
-	int expression_vol;	/* midi expression (0-127) */
-	int chan_press;		/* channel pressure */
-	int sustained;		/* sustain status in MIDI */
-	FX_Rec fx;		/* effects */
-	FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
-} awe_chan_info;
-
-/* voice parameters */
-typedef struct _voice_info {
-	int state;
-#define AWE_ST_OFF		(1<<0)	/* no sound */
-#define AWE_ST_ON		(1<<1)	/* playing */
-#define AWE_ST_STANDBY		(1<<2)	/* stand by for playing */
-#define AWE_ST_SUSTAINED	(1<<3)	/* sustained */
-#define AWE_ST_MARK		(1<<4)	/* marked for allocation */
-#define AWE_ST_DRAM		(1<<5)	/* DRAM read/write */
-#define AWE_ST_FM		(1<<6)	/* reserved for FM */
-#define AWE_ST_RELEASED		(1<<7)	/* released */
-
-	int ch;			/* midi channel */
-	int key;		/* internal key for search */
-	int layer;		/* layer number (for channel mode only) */
-	int time;		/* allocated time */
-	awe_chan_info	*cinfo;	/* channel info */
-
-	int note;		/* midi key (0-127) */
-	int velocity;		/* midi velocity (0-127) */
-	int sostenuto;		/* sostenuto on/off */
-	awe_voice_info *sample;	/* assigned voice */
-
-	/* EMU8000 parameters */
-	int apitch;		/* pitch parameter */
-	int avol;		/* volume parameter */
-	int apan;		/* panning parameter */
-	int acutoff;		/* cutoff parameter */
-	short aaux;		/* aux word */
-} voice_info;
-
-/* voice information */
-static voice_info voices[AWE_MAX_VOICES];
-
-#define IS_NO_SOUND(v)	(voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))
-#define IS_NO_EFFECT(v)	(voices[v].state != AWE_ST_ON)
-#define IS_PLAYING(v)	(voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))
-#define IS_EMPTY(v)	(voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))
-
-
-/* MIDI channel effects information (for hw control) */
-static awe_chan_info channels[AWE_MAX_CHANNELS];
-
-
-/*
- * global variables
- */
-
-#ifndef AWE_DEFAULT_BASE_ADDR
-#define AWE_DEFAULT_BASE_ADDR	0	/* autodetect */
-#endif
-
-#ifndef AWE_DEFAULT_MEM_SIZE
-#define AWE_DEFAULT_MEM_SIZE	-1	/* autodetect */
-#endif
-
-static int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
-static int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
-#ifdef CONFIG_PNP
-static int isapnp = -1;
-#else
-static int isapnp;
-#endif
-
-MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
-MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "base i/o port of Emu8000");
-module_param(memsize, int, 0);
-MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp, "use ISAPnP detection");
-
-/* DRAM start offset */
-static int awe_mem_start = AWE_DRAM_OFFSET;
-
-/* maximum channels for playing */
-static int awe_max_voices = AWE_MAX_VOICES;
-
-static int patch_opened;		/* sample already loaded? */
-
-static char atten_relative = FALSE;
-static short atten_offset;
-
-static int awe_present = FALSE;		/* awe device present? */
-static int awe_busy = FALSE;		/* awe device opened? */
-
-static int my_dev = -1;
-
-#define DEFAULT_DRUM_FLAGS	((1 << 9) | (1 << 25))
-#define IS_DRUM_CHANNEL(c)	(drum_flags & (1 << (c)))
-#define DRUM_CHANNEL_ON(c)	(drum_flags |= (1 << (c)))
-#define DRUM_CHANNEL_OFF(c)	(drum_flags &= ~(1 << (c)))
-static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */
-
-static int playing_mode = AWE_PLAY_INDIRECT;
-#define SINGLE_LAYER_MODE()	(playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT)
-#define MULTI_LAYER_MODE()	(playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2)
-
-static int current_alloc_time;  	/* voice allocation index for channel mode */
-
-static struct synth_info awe_info = {
-	"AWE32 Synth",		/* name */
-	0,			/* device */
-	SYNTH_TYPE_SAMPLE,	/* synth_type */
-	SAMPLE_TYPE_AWE32,	/* synth_subtype */
-	0,			/* perc_mode (obsolete) */
-	AWE_MAX_VOICES,		/* nr_voices */
-	0,			/* nr_drums (obsolete) */
-	400			/* instr_bank_size */
-};
-
-
-static struct voice_alloc_info *voice_alloc;	/* set at initialization */
-
-
-/*
- * function prototypes
- */
-
-static int awe_request_region(void);
-static void awe_release_region(void);
-
-static void awe_reset_samples(void);
-/* emu8000 chip i/o access */
-static void setup_ports(int p1, int p2, int p3);
-static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);
-static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data);
-static unsigned short awe_peek(unsigned short cmd, unsigned short port);
-static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port);
-static void awe_wait(unsigned short delay);
-
-/* initialize emu8000 chip */
-static void awe_initialize(void);
-
-/* set voice parameters */
-static void awe_init_ctrl_parms(int init_all);
-static void awe_init_voice_info(awe_voice_info *vp);
-static void awe_init_voice_parm(awe_voice_parm *pp);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int freq_to_note(int freq);
-static int calc_rate_offset(int Hz);
-/*static int calc_parm_delay(int msec);*/
-static int calc_parm_hold(int msec);
-static int calc_parm_attack(int msec);
-static int calc_parm_decay(int msec);
-static int calc_parm_search(int msec, short *table);
-#endif /* gus compat */
-
-/* turn on/off note */
-static void awe_note_on(int voice);
-static void awe_note_off(int voice);
-static void awe_terminate(int voice);
-static void awe_exclusive_off(int voice);
-static void awe_note_off_all(int do_sustain);
-
-/* calculate voice parameters */
-typedef void (*fx_affect_func)(int voice, int forced);
-static void awe_set_pitch(int voice, int forced);
-static void awe_set_voice_pitch(int voice, int forced);
-static void awe_set_volume(int voice, int forced);
-static void awe_set_voice_vol(int voice, int forced);
-static void awe_set_pan(int voice, int forced);
-static void awe_fx_fmmod(int voice, int forced);
-static void awe_fx_tremfrq(int voice, int forced);
-static void awe_fx_fm2frq2(int voice, int forced);
-static void awe_fx_filterQ(int voice, int forced);
-static void awe_calc_pitch(int voice);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_calc_pitch_from_freq(int voice, int freq);
-#endif
-static void awe_calc_volume(int voice);
-static void awe_update_volume(void);
-static void awe_change_master_volume(short val);
-static void awe_voice_init(int voice, int init_all);
-static void awe_channel_init(int ch, int init_all);
-static void awe_fx_init(int ch);
-static void awe_send_effect(int voice, int layer, int type, int val);
-static void awe_modwheel_change(int voice, int value);
-
-/* sequencer interface */
-static int awe_open(int dev, int mode);
-static void awe_close(int dev);
-static int awe_ioctl(int dev, unsigned int cmd, void __user * arg);
-static int awe_kill_note(int dev, int voice, int note, int velocity);
-static int awe_start_note(int dev, int v, int note_num, int volume);
-static int awe_set_instr(int dev, int voice, int instr_no);
-static int awe_set_instr_2(int dev, int voice, int instr_no);
-static void awe_reset(int dev);
-static void awe_hw_control(int dev, unsigned char *event);
-static int awe_load_patch(int dev, int format, const char __user *addr,
-			  int offs, int count, int pmgr_flag);
-static void awe_aftertouch(int dev, int voice, int pressure);
-static void awe_controller(int dev, int voice, int ctrl_num, int value);
-static void awe_panning(int dev, int voice, int value);
-static void awe_volume_method(int dev, int mode);
-static void awe_bender(int dev, int voice, int value);
-static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
-static void awe_setup_voice(int dev, int voice, int chn);
-
-#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press)
-
-/* hardware controls */
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_hw_gus_control(int dev, int cmd, unsigned char *event);
-#endif
-static void awe_hw_awe_control(int dev, int cmd, unsigned char *event);
-static void awe_voice_change(int voice, fx_affect_func func);
-static void awe_sostenuto_on(int voice, int forced);
-static void awe_sustain_off(int voice, int forced);
-static void awe_terminate_and_init(int voice, int forced);
-
-/* voice search */
-static int awe_search_key(int bank, int preset, int note);
-static awe_voice_list *awe_search_instr(int bank, int preset, int note);
-static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist);
-static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
-static void awe_alloc_one_voice(int voice, int note, int velocity);
-static int awe_clear_voice(void);
-
-/* load / remove patches */
-static int awe_open_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_close_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_info(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_remove_info(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_data(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_replace_data(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_map(awe_patch_info *patch, const char __user *addr, int count);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag);
-#endif
-/*static int awe_probe_info(awe_patch_info *patch, const char __user *addr, int count);*/
-static int awe_probe_data(awe_patch_info *patch, const char __user *addr, int count);
-static sf_list *check_patch_opened(int type, char *name);
-static int awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *sp, int channels);
-static int awe_create_sf(int type, char *name);
-static void awe_free_sf(sf_list *sf);
-static void add_sf_info(sf_list *sf, awe_voice_list *rec);
-static void add_sf_sample(sf_list *sf, awe_sample_list *smp);
-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next);
-static void add_info_list(awe_voice_list *rec);
-static void awe_remove_samples(int sf_id);
-static void rebuild_preset_list(void);
-static short awe_set_sample(awe_voice_list *rec);
-static awe_sample_list *search_sample_index(sf_list *sf, int sample);
-
-static int is_identical_holder(sf_list *sf1, sf_list *sf2);
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-static int is_identical_name(unsigned char *name, sf_list *p);
-static int is_shared_sf(unsigned char *name);
-static int info_duplicated(sf_list *sf, awe_voice_list *rec);
-#endif /* allow sharing */
-
-/* lowlevel functions */
-static void awe_init_audio(void);
-static void awe_init_dma(void);
-static void awe_init_array(void);
-static void awe_send_array(unsigned short *data);
-static void awe_tweak_voice(int voice);
-static void awe_tweak(void);
-static void awe_init_fm(void);
-static int awe_open_dram_for_write(int offset, int channels);
-static void awe_open_dram_for_check(void);
-static void awe_close_dram(void);
-/*static void awe_write_dram(unsigned short c);*/
-static int awe_detect_base(int addr);
-static int awe_detect(void);
-static void awe_check_dram(void);
-static int awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count);
-static void awe_set_chorus_mode(int mode);
-static void awe_update_chorus_mode(void);
-static int awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count);
-static void awe_set_reverb_mode(int mode);
-static void awe_update_reverb_mode(void);
-static void awe_equalizer(int bass, int treble);
-static void awe_update_equalizer(void);
-
-#ifdef CONFIG_AWE32_MIXER
-static void attach_mixer(void);
-static void unload_mixer(void);
-#endif
-
-#ifdef CONFIG_AWE32_MIDIEMU
-static void attach_midiemu(void);
-static void unload_midiemu(void);
-#endif
-
-#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)
-
-/*
- * control parameters
- */
-
-
-#ifdef AWE_USE_NEW_VOLUME_CALC
-#define DEF_VOLUME_CALC	TRUE
-#else
-#define DEF_VOLUME_CALC	FALSE
-#endif /* new volume */
-
-#define DEF_ZERO_ATTEN		32	/* 12dB below */
-#define DEF_MOD_SENSE		18
-#define DEF_CHORUS_MODE		2
-#define DEF_REVERB_MODE		4
-#define DEF_BASS_LEVEL		5
-#define DEF_TREBLE_LEVEL	9
-
-static struct CtrlParmsDef {
-	int value;
-	int init_each_time;
-	void (*update)(void);
-} ctrl_parms[AWE_MD_END] = {
-	{0,0, NULL}, {0,0, NULL}, /* <-- not used */
-	{AWE_VERSION_NUMBER, FALSE, NULL},
-	{TRUE, FALSE, NULL}, /* exclusive */
-	{TRUE, FALSE, NULL}, /* realpan */
-	{AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */
-	{FALSE, TRUE, NULL}, /* keep effect */
-	{DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */
-	{FALSE, FALSE, NULL}, /* chn_prior */
-	{DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */
-	{AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */
-	{AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */
-	{AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */
-	{FALSE, FALSE, NULL}, /* toggle_drum_bank */
-	{DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */
-	{DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */
-	{DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */
-	{DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */
-	{DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */
-	{0, FALSE, NULL},	/* debug mode */
-	{FALSE, FALSE, NULL}, /* pan exchange */
-};
-
-static int ctrls[AWE_MD_END];
-
-
-/*
- * synth operation table
- */
-
-static struct synth_operations awe_operations =
-{
-	.owner		= THIS_MODULE,
-	.id		= "EMU8K",
-	.info		= &awe_info,
-	.midi_dev	= 0,
-	.synth_type	= SYNTH_TYPE_SAMPLE,
-	.synth_subtype	= SAMPLE_TYPE_AWE32,
-	.open		= awe_open,
-	.close		= awe_close,
-	.ioctl		= awe_ioctl,
-	.kill_note	= awe_kill_note,
-	.start_note	= awe_start_note,
-	.set_instr	= awe_set_instr_2,
-	.reset		= awe_reset,
-	.hw_control	= awe_hw_control,
-	.load_patch	= awe_load_patch,
-	.aftertouch	= awe_aftertouch,
-	.controller	= awe_controller,
-	.panning	= awe_panning,
-	.volume_method	= awe_volume_method,
-	.bender		= awe_bender,
-	.alloc_voice	= awe_alloc,
-	.setup_voice	= awe_setup_voice
-};
-
-static void free_tables(void)
-{
-	if (sftail) {
-		sf_list *p, *prev;
-		for (p = sftail; p; p = prev) {
-			prev = p->prev;
-			awe_free_sf(p);
-		}
-	}
-	sfhead = sftail = NULL;
-}
-
-/*
- * clear sample tables 
- */
-
-static void
-awe_reset_samples(void)
-{
-	/* free all bank tables */
-	memset(preset_table, 0, sizeof(preset_table));
-	free_tables();
-
-	current_sf_id = 0;
-	locked_sf_id = 0;
-	patch_opened = 0;
-}
-
-
-/*
- * EMU register access
- */
-
-/* select a given AWE32 pointer */
-static int awe_ports[5];
-static int port_setuped = FALSE;
-static int awe_cur_cmd = -1;
-#define awe_set_cmd(cmd) \
-if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
-
-/* write 16bit data */
-static void
-awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
-{
-	awe_set_cmd(cmd);
-	outw(data, awe_ports[port]);
-}
-
-/* write 32bit data */
-static void
-awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
-{
-	unsigned short addr = awe_ports[port];
-	awe_set_cmd(cmd);
-	outw(data, addr);		/* write lower 16 bits */
-	outw(data >> 16, addr + 2);	/* write higher 16 bits */
-}
-
-/* read 16bit data */
-static unsigned short
-awe_peek(unsigned short cmd, unsigned short port)
-{
-	unsigned short k;
-	awe_set_cmd(cmd);
-	k = inw(awe_ports[port]);
-	return k;
-}
-
-/* read 32bit data */
-static unsigned int
-awe_peek_dw(unsigned short cmd, unsigned short port)
-{
-	unsigned int k1, k2;
-	unsigned short addr = awe_ports[port];
-	awe_set_cmd(cmd);
-	k1 = inw(addr);
-	k2 = inw(addr + 2);
-	k1 |= k2 << 16;
-	return k1;
-}
-
-/* wait delay number of AWE32 44100Hz clocks */
-#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */
-static void
-awe_wait(unsigned short delay)
-{
-	unsigned short clock, target;
-	unsigned short port = awe_ports[AWE_WC_Port];
-	int counter;
-  
-	/* sample counter */
-	awe_set_cmd(AWE_WC_Cmd);
-	clock = (unsigned short)inw(port);
-	target = clock + delay;
-	counter = 0;
-	if (target < clock) {
-		for (; (unsigned short)inw(port) > target; counter++)
-			if (counter > 65536)
-				break;
-	}
-	for (; (unsigned short)inw(port) < target; counter++)
-		if (counter > 65536)
-			break;
-}
-#else
-
-static void awe_wait(unsigned short delay)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
-}
-/*
-static void awe_wait(unsigned short delay)
-{
-	udelay(((unsigned long)delay * 1000000L + 44099) / 44100);
-}
-*/
-#endif /* wait by loop */
-
-/* write a word data */
-#define awe_write_dram(c)	awe_poke(AWE_SMLD, c)
-
-/*
- * AWE32 voice parameters
- */
-
-/* initialize voice_info record */
-static void
-awe_init_voice_info(awe_voice_info *vp)
-{
-	vp->sample = 0;
-	vp->rate_offset = 0;
-
-	vp->start = 0;
-	vp->end = 0;
-	vp->loopstart = 0;
-	vp->loopend = 0;
-	vp->mode = 0;
-	vp->root = 60;
-	vp->tune = 0;
-	vp->low = 0;
-	vp->high = 127;
-	vp->vellow = 0;
-	vp->velhigh = 127;
-
-	vp->fixkey = -1;
-	vp->fixvel = -1;
-	vp->fixpan = -1;
-	vp->pan = -1;
-
-	vp->exclusiveClass = 0;
-	vp->amplitude = 127;
-	vp->attenuation = 0;
-	vp->scaleTuning = 100;
-
-	awe_init_voice_parm(&vp->parm);
-}
-
-/* initialize voice_parm record:
- * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
- * Vibrato and Tremolo effects are zero.
- * Cutoff is maximum.
- * Chorus and Reverb effects are zero.
- */
-static void
-awe_init_voice_parm(awe_voice_parm *pp)
-{
-	pp->moddelay = 0x8000;
-	pp->modatkhld = 0x7f7f;
-	pp->moddcysus = 0x7f7f;
-	pp->modrelease = 0x807f;
-	pp->modkeyhold = 0;
-	pp->modkeydecay = 0;
-
-	pp->voldelay = 0x8000;
-	pp->volatkhld = 0x7f7f;
-	pp->voldcysus = 0x7f7f;
-	pp->volrelease = 0x807f;
-	pp->volkeyhold = 0;
-	pp->volkeydecay = 0;
-
-	pp->lfo1delay = 0x8000;
-	pp->lfo2delay = 0x8000;
-	pp->pefe = 0;
-
-	pp->fmmod = 0;
-	pp->tremfrq = 0;
-	pp->fm2frq2 = 0;
-
-	pp->cutoff = 0xff;
-	pp->filterQ = 0;
-
-	pp->chorus = 0;
-	pp->reverb = 0;
-}	
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* convert frequency mHz to abstract cents (= midi key * 100) */
-static int
-freq_to_note(int mHz)
-{
-	/* abscents = log(mHz/8176) / log(2) * 1200 */
-	unsigned int max_val = (unsigned int)0xffffffff / 10000;
-	int i, times;
-	unsigned int base;
-	unsigned int freq;
-	int note, tune;
-
-	if (mHz == 0)
-		return 0;
-	if (mHz < 0)
-		return 12799; /* maximum */
-
-	freq = mHz;
-	note = 0;
-	for (base = 8176 * 2; freq >= base; base *= 2) {
-		note += 12;
-		if (note >= 128) /* over maximum */
-			return 12799;
-	}
-	base /= 2;
-
-	/* to avoid overflow... */
-	times = 10000;
-	while (freq > max_val) {
-		max_val *= 10;
-		times /= 10;
-		base /= 10;
-	}
-
-	freq = freq * times / base;
-	for (i = 0; i < 12; i++) {
-		if (freq < semitone_tuning[i+1])
-			break;
-		note++;
-	}
-
-	tune = 0;
-	freq = freq * 10000 / semitone_tuning[i];
-	for (i = 0; i < 100; i++) {
-		if (freq < cent_tuning[i+1])
-			break;
-		tune++;
-	}
-
-	return note * 100 + tune;
-}
-
-
-/* convert Hz to AWE32 rate offset:
- * sample pitch offset for the specified sample rate
- * rate=44100 is no offset, each 4096 is 1 octave (twice).
- * eg, when rate is 22050, this offset becomes -4096.
- */
-static int
-calc_rate_offset(int Hz)
-{
-	/* offset = log(Hz / 44100) / log(2) * 4096 */
-	int freq, base, i;
-
-	/* maybe smaller than max (44100Hz) */
-	if (Hz <= 0 || Hz >= 44100) return 0;
-
-	base = 0;
-	for (freq = Hz * 2; freq < 44100; freq *= 2)
-		base++;
-	base *= 1200;
-
-	freq = 44100 * 10000 / (freq/2);
-	for (i = 0; i < 12; i++) {
-		if (freq < semitone_tuning[i+1])
-			break;
-		base += 100;
-	}
-	freq = freq * 10000 / semitone_tuning[i];
-	for (i = 0; i < 100; i++) {
-		if (freq < cent_tuning[i+1])
-			break;
-		base++;
-	}
-	return -base * 4096 / 1200;
-}
-
-
-/*
- * convert envelope time parameter to AWE32 raw parameter
- */
-
-/* attack & decay/release time table (msec) */
-static short attack_time_tbl[128] = {
-32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,
-707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,
-361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,
-180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,
-90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,
-45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,
-22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
-11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,
-};
-
-static short decay_time_tbl[128] = {
-32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
-2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
-1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,
-691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,
-345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,
-172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,
-86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,
-43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,
-};
-
-#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725);
-
-/* delay time = 0x8000 - msec/92 */
-static int
-calc_parm_hold(int msec)
-{
-	int val = (0x7f * 92 - msec) / 92;
-	if (val < 1) val = 1;
-	if (val > 127) val = 127;
-	return val;
-}
-
-/* attack time: search from time table */
-static int
-calc_parm_attack(int msec)
-{
-	return calc_parm_search(msec, attack_time_tbl);
-}
-
-/* decay/release time: search from time table */
-static int
-calc_parm_decay(int msec)
-{
-	return calc_parm_search(msec, decay_time_tbl);
-}
-
-/* search an index for specified time from given time table */
-static int
-calc_parm_search(int msec, short *table)
-{
-	int left = 1, right = 127, mid;
-	while (left < right) {
-		mid = (left + right) / 2;
-		if (msec < (int)table[mid])
-			left = mid + 1;
-		else
-			right = mid;
-	}
-	return left;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*
- * effects table
- */
-
-/* set an effect value */
-#define FX_FLAG_OFF	0
-#define FX_FLAG_SET	1
-#define FX_FLAG_ADD	2
-
-#define FX_SET(rec,type,value) \
-	((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value))
-#define FX_ADD(rec,type,value) \
-	((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value))
-#define FX_UNSET(rec,type) \
-	((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0)
-
-/* check the effect value is set */
-#define FX_ON(rec,type)	((rec)->flags[type])
-
-#define PARM_BYTE	0
-#define PARM_WORD	1
-#define PARM_SIGN	2
-
-static struct PARM_DEFS {
-	int type;	/* byte or word */
-	int low, high;	/* value range */
-	fx_affect_func realtime;	/* realtime paramater change */
-} parm_defs[] = {
-	{PARM_WORD, 0, 0x8000, NULL},	/* env1 delay */
-	{PARM_BYTE, 1, 0x7f, NULL},	/* env1 attack */
-	{PARM_BYTE, 0, 0x7e, NULL},	/* env1 hold */
-	{PARM_BYTE, 1, 0x7f, NULL},	/* env1 decay */
-	{PARM_BYTE, 1, 0x7f, NULL},	/* env1 release */
-	{PARM_BYTE, 0, 0x7f, NULL},	/* env1 sustain */
-	{PARM_BYTE, 0, 0xff, NULL},	/* env1 pitch */
-	{PARM_BYTE, 0, 0xff, NULL},	/* env1 cutoff */
-
-	{PARM_WORD, 0, 0x8000, NULL},	/* env2 delay */
-	{PARM_BYTE, 1, 0x7f, NULL},	/* env2 attack */
-	{PARM_BYTE, 0, 0x7e, NULL},	/* env2 hold */
-	{PARM_BYTE, 1, 0x7f, NULL},	/* env2 decay */
-	{PARM_BYTE, 1, 0x7f, NULL},	/* env2 release */
-	{PARM_BYTE, 0, 0x7f, NULL},	/* env2 sustain */
-
-	{PARM_WORD, 0, 0x8000, NULL},	/* lfo1 delay */
-	{PARM_BYTE, 0, 0xff, awe_fx_tremfrq},	/* lfo1 freq */
-	{PARM_SIGN, -128, 127, awe_fx_tremfrq},	/* lfo1 volume */
-	{PARM_SIGN, -128, 127, awe_fx_fmmod},	/* lfo1 pitch */
-	{PARM_BYTE, 0, 0xff, awe_fx_fmmod},	/* lfo1 cutoff */
-
-	{PARM_WORD, 0, 0x8000, NULL},	/* lfo2 delay */
-	{PARM_BYTE, 0, 0xff, awe_fx_fm2frq2},	/* lfo2 freq */
-	{PARM_SIGN, -128, 127, awe_fx_fm2frq2},	/* lfo2 pitch */
-
-	{PARM_WORD, 0, 0xffff, awe_set_voice_pitch},	/* initial pitch */
-	{PARM_BYTE, 0, 0xff, NULL},	/* chorus */
-	{PARM_BYTE, 0, 0xff, NULL},	/* reverb */
-	{PARM_BYTE, 0, 0xff, awe_set_volume},	/* initial cutoff */
-	{PARM_BYTE, 0, 15, awe_fx_filterQ},	/* initial resonance */
-
-	{PARM_WORD, 0, 0xffff, NULL},	/* sample start */
-	{PARM_WORD, 0, 0xffff, NULL},	/* loop start */
-	{PARM_WORD, 0, 0xffff, NULL},	/* loop end */
-	{PARM_WORD, 0, 0xffff, NULL},	/* coarse sample start */
-	{PARM_WORD, 0, 0xffff, NULL},	/* coarse loop start */
-	{PARM_WORD, 0, 0xffff, NULL},	/* coarse loop end */
-	{PARM_BYTE, 0, 0xff, awe_set_volume},	/* initial attenuation */
-};
-
-
-static unsigned char
-FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value)
-{
-	int effect = 0;
-	int on = 0;
-	if (lay && (on = FX_ON(lay, type)) != 0)
-		effect = lay->val[type];
-	if (!on && (on = FX_ON(rec, type)) != 0)
-		effect = rec->val[type];
-	if (on == FX_FLAG_ADD) {
-		if (parm_defs[type].type == PARM_SIGN) {
-			if (value > 0x7f)
-				effect += (int)value - 0x100;
-			else
-				effect += (int)value;
-		} else {
-			effect += (int)value;
-		}
-	}
-	if (on) {
-		if (effect < parm_defs[type].low)
-			effect = parm_defs[type].low;
-		else if (effect > parm_defs[type].high)
-			effect = parm_defs[type].high;
-		return (unsigned char)effect;
-	}
-	return value;
-}
-
-/* get word effect value */
-static unsigned short
-FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value)
-{
-	int effect = 0;
-	int on = 0;
-	if (lay && (on = FX_ON(lay, type)) != 0)
-		effect = lay->val[type];
-	if (!on && (on = FX_ON(rec, type)) != 0)
-		effect = rec->val[type];
-	if (on == FX_FLAG_ADD)
-		effect += (int)value;
-	if (on) {
-		if (effect < parm_defs[type].low)
-			effect = parm_defs[type].low;
-		else if (effect > parm_defs[type].high)
-			effect = parm_defs[type].high;
-		return (unsigned short)effect;
-	}
-	return value;
-}
-
-/* get word (upper=type1/lower=type2) effect value */
-static unsigned short
-FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value)
-{
-	unsigned short tmp;
-	tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8));
-	tmp <<= 8;
-	tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff));
-	return tmp;
-}
-
-/* address offset */
-static int
-FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode)
-{
-	int addr = 0;
-	if (lay && FX_ON(lay, hi))
-		addr = (short)lay->val[hi];
-	else if (FX_ON(rec, hi))
-		addr = (short)rec->val[hi];
-	addr = addr << 15;
-	if (lay && FX_ON(lay, lo))
-		addr += (short)lay->val[lo];
-	else if (FX_ON(rec, lo))
-		addr += (short)rec->val[lo];
-	if (!(mode & AWE_SAMPLE_8BITS))
-		addr /= 2;
-	return addr;
-}
-
-
-/*
- * turn on/off sample
- */
-
-/* table for volume target calculation */
-static unsigned short voltarget[16] = { 
-   0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58,
-   0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90
-};
-
-static void
-awe_note_on(int voice)
-{
-	unsigned int temp;
-	int addr;
-	int vtarget, ftarget, ptarget, pitch;
-	awe_voice_info *vp;
-	awe_voice_parm_block *parm;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	/* A voice sample must assigned before calling */
-	if ((vp = voices[voice].sample) == NULL || vp->index == 0)
-		return;
-
-	parm = (awe_voice_parm_block*)&vp->parm;
-
-	/* channel to be silent and idle */
-	awe_poke(AWE_DCYSUSV(voice), 0x0080);
-	awe_poke(AWE_VTFT(voice), 0x0000FFFF);
-	awe_poke(AWE_CVCF(voice), 0x0000FFFF);
-	awe_poke(AWE_PTRX(voice), 0);
-	awe_poke(AWE_CPF(voice), 0);
-
-	/* set pitch offset */
-	awe_set_pitch(voice, TRUE);
-
-	/* modulation & volume envelope */
-	if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) {
-		awe_poke(AWE_ENVVAL(voice), 0xBFFF);
-		pitch = (parm->env1pit<<4) + voices[voice].apitch;
-		if (pitch > 0xffff) pitch = 0xffff;
-		/* calculate filter target */
-		ftarget = parm->cutoff + parm->env1fc;
-		limitvalue(ftarget, 0, 255);
-		ftarget <<= 8;
-	} else {
-		awe_poke(AWE_ENVVAL(voice),
-			 FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay));
-		ftarget = parm->cutoff;
-		ftarget <<= 8;
-		pitch = voices[voice].apitch;
-	}
-
-	/* calcualte pitch target */
-	if (pitch != 0xffff) {
-		ptarget = 1 << (pitch >> 12);
-		if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710;
-		if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710;
-		if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710;
-		ptarget += (ptarget>>1);
-		if (ptarget > 0xffff) ptarget = 0xffff;
-
-	} else ptarget = 0xffff;
-	if (parm->modatk >= 0x80)
-		awe_poke(AWE_ATKHLD(voice),
-			 FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f);
-	else
-		awe_poke(AWE_ATKHLD(voice),
-			 FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK,
-				 vp->parm.modatkhld));
-	awe_poke(AWE_DCYSUS(voice),
-		 FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY,
-			  vp->parm.moddcysus));
-
-	if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) {
-		awe_poke(AWE_ENVVOL(voice), 0xBFFF);
-		vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4);
-	} else {
-		awe_poke(AWE_ENVVOL(voice),
-			 FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay));
-		vtarget = 0;
-	}
-	if (parm->volatk >= 0x80)
-		awe_poke(AWE_ATKHLDV(voice),
-			 FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f);
-	else
-		awe_poke(AWE_ATKHLDV(voice),
-			 FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK,
-			 vp->parm.volatkhld));
-	/* decay/sustain parameter for volume envelope must be set at last */
-
-	/* cutoff and volume */
-	awe_set_volume(voice, TRUE);
-
-	/* modulation envelope heights */
-	awe_poke(AWE_PEFE(voice),
-		 FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF,
-			 vp->parm.pefe));
-
-	/* lfo1/2 delay */
-	awe_poke(AWE_LFO1VAL(voice),
-		 FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay));
-	awe_poke(AWE_LFO2VAL(voice),
-		 FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay));
-
-	/* lfo1 pitch & cutoff shift */
-	awe_fx_fmmod(voice, TRUE);
-	/* lfo1 volume & freq */
-	awe_fx_tremfrq(voice, TRUE);
-	/* lfo2 pitch & freq */
-	awe_fx_fm2frq2(voice, TRUE);
-	/* pan & loop start */
-	awe_set_pan(voice, TRUE);
-
-	/* chorus & loop end (chorus 8bit, MSB) */
-	addr = vp->loopend - 1;
-	addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END,
-			  AWE_FX_COARSE_LOOP_END, vp->mode);
-	temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus);
-	temp = (temp <<24) | (unsigned int)addr;
-	awe_poke_dw(AWE_CSL(voice), temp);
-	DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr));
-
-	/* Q & current address (Q 4bit value, MSB) */
-	addr = vp->start - 1;
-	addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START,
-			  AWE_FX_COARSE_SAMPLE_START, vp->mode);
-	temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ);
-	temp = (temp<<28) | (unsigned int)addr;
-	awe_poke_dw(AWE_CCCA(voice), temp);
-	DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr));
-
-	/* clear unknown registers */
-	awe_poke_dw(AWE_00A0(voice), 0);
-	awe_poke_dw(AWE_0080(voice), 0);
-
-	/* reset volume */
-	awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
-	awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
-
-	/* set reverb */
-	temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
-	temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
-	awe_poke_dw(AWE_PTRX(voice), temp);
-	awe_poke_dw(AWE_CPF(voice), ptarget << 16);
-	/* turn on envelope */
-	awe_poke(AWE_DCYSUSV(voice),
-		 FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
-			  vp->parm.voldcysus));
-
-	voices[voice].state = AWE_ST_ON;
-
-	/* clear voice position for the next note on this channel */
-	if (SINGLE_LAYER_MODE()) {
-		FX_UNSET(fx, AWE_FX_SAMPLE_START);
-		FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START);
-	}
-}
-
-
-/* turn off the voice */
-static void
-awe_note_off(int voice)
-{
-	awe_voice_info *vp;
-	unsigned short tmp;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	if ((vp = voices[voice].sample) == NULL) {
-		voices[voice].state = AWE_ST_OFF;
-		return;
-	}
-
-	tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE,
-			       (unsigned char)vp->parm.modrelease);
-	awe_poke(AWE_DCYSUS(voice), tmp);
-	tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE,
-			       (unsigned char)vp->parm.volrelease);
-	awe_poke(AWE_DCYSUSV(voice), tmp);
-	voices[voice].state = AWE_ST_RELEASED;
-}
-
-/* force to terminate the voice (no releasing echo) */
-static void
-awe_terminate(int voice)
-{
-	awe_poke(AWE_DCYSUSV(voice), 0x807F);
-	awe_tweak_voice(voice);
-	voices[voice].state = AWE_ST_OFF;
-}
-
-/* turn off other voices with the same exclusive class (for drums) */
-static void
-awe_exclusive_off(int voice)
-{
-	int i, exclass;
-
-	if (voices[voice].sample == NULL)
-		return;
-	if ((exclass = voices[voice].sample->exclusiveClass) == 0)
-		return;	/* not exclusive */
-
-	/* turn off voices with the same class */
-	for (i = 0; i < awe_max_voices; i++) {
-		if (i != voice && IS_PLAYING(i) &&
-		    voices[i].sample && voices[i].ch == voices[voice].ch &&
-		    voices[i].sample->exclusiveClass == exclass) {
-			DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
-			awe_terminate(i);
-			awe_voice_init(i, TRUE);
-		}
-	}
-}
-
-
-/*
- * change the parameters of an audible voice
- */
-
-/* change pitch */
-static void
-awe_set_pitch(int voice, int forced)
-{
-	if (IS_NO_EFFECT(voice) && !forced) return;
-	awe_poke(AWE_IP(voice), voices[voice].apitch);
-	DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch));
-}
-
-/* calculate & change pitch */
-static void
-awe_set_voice_pitch(int voice, int forced)
-{
-	awe_calc_pitch(voice);
-	awe_set_pitch(voice, forced);
-}
-
-/* change volume & cutoff */
-static void
-awe_set_volume(int voice, int forced)
-{
-	awe_voice_info *vp;
-	unsigned short tmp2;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	if (!IS_PLAYING(voice) && !forced) return;
-	if ((vp = voices[voice].sample) == NULL || vp->index == 0)
-		return;
-
-	tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
-		       (unsigned char)voices[voice].acutoff);
-	tmp2 = (tmp2 << 8);
-	tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN,
-			(unsigned char)voices[voice].avol);
-	awe_poke(AWE_IFATN(voice), tmp2);
-}
-
-/* calculate & change volume */
-static void
-awe_set_voice_vol(int voice, int forced)
-{
-	if (IS_EMPTY(voice))
-		return;
-	awe_calc_volume(voice);
-	awe_set_volume(voice, forced);
-}
-
-
-/* change pan; this could make a click noise.. */
-static void
-awe_set_pan(int voice, int forced)
-{
-	unsigned int temp;
-	int addr;
-	awe_voice_info *vp;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	if (IS_NO_EFFECT(voice) && !forced) return;
-	if ((vp = voices[voice].sample) == NULL || vp->index == 0)
-		return;
-
-	/* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
-	if (vp->fixpan > 0)	/* 0-127 */
-		temp = 255 - (int)vp->fixpan * 2;
-	else {
-		int pos = 0;
-		if (vp->pan >= 0) /* 0-127 */
-			pos = (int)vp->pan * 2 - 128;
-		pos += voices[voice].cinfo->panning; /* -128 - 127 */
-		temp = 127 - pos;
-	}
-	limitvalue(temp, 0, 255);
-	if (ctrls[AWE_MD_PAN_EXCHANGE]) {
-		temp = 255 - temp;
-	}
-	if (forced || temp != voices[voice].apan) {
-		voices[voice].apan = temp;
-		if (temp == 0)
-			voices[voice].aaux = 0xff;
-		else
-			voices[voice].aaux = (-temp) & 0xff;
-		addr = vp->loopstart - 1;
-		addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
-				  AWE_FX_COARSE_LOOP_START, vp->mode);
-		temp = (temp<<24) | (unsigned int)addr;
-		awe_poke_dw(AWE_PSST(voice), temp);
-		DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
-	}
-}
-
-/* effects change during playing */
-static void
-awe_fx_fmmod(int voice, int forced)
-{
-	awe_voice_info *vp;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	if (IS_NO_EFFECT(voice) && !forced) return;
-	if ((vp = voices[voice].sample) == NULL || vp->index == 0)
-		return;
-	awe_poke(AWE_FMMOD(voice),
-		 FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
-			 vp->parm.fmmod));
-}
-
-/* set tremolo (lfo1) volume & frequency */
-static void
-awe_fx_tremfrq(int voice, int forced)
-{
-	awe_voice_info *vp;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	if (IS_NO_EFFECT(voice) && !forced) return;
-	if ((vp = voices[voice].sample) == NULL || vp->index == 0)
-		return;
-	awe_poke(AWE_TREMFRQ(voice),
-		 FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
-			 vp->parm.tremfrq));
-}
-
-/* set lfo2 pitch & frequency */
-static void
-awe_fx_fm2frq2(int voice, int forced)
-{
-	awe_voice_info *vp;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	if (IS_NO_EFFECT(voice) && !forced) return;
-	if ((vp = voices[voice].sample) == NULL || vp->index == 0)
-		return;
-	awe_poke(AWE_FM2FRQ2(voice),
-		 FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
-			 vp->parm.fm2frq2));
-}
-
-
-/* Q & current address (Q 4bit value, MSB) */
-static void
-awe_fx_filterQ(int voice, int forced)
-{
-	unsigned int addr;
-	awe_voice_info *vp;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	if (IS_NO_EFFECT(voice) && !forced) return;
-	if ((vp = voices[voice].sample) == NULL || vp->index == 0)
-		return;
-
-	addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
-	addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28);
-	awe_poke_dw(AWE_CCCA(voice), addr);
-}
-
-/*
- * calculate pitch offset
- *
- * 0xE000 is no pitch offset at 44100Hz sample.
- * Every 4096 is one octave.
- */
-
-static void
-awe_calc_pitch(int voice)
-{
-	voice_info *vp = &voices[voice];
-	awe_voice_info *ap;
-	awe_chan_info *cp = voices[voice].cinfo;
-	int offset;
-
-	/* search voice information */
-	if ((ap = vp->sample) == NULL)
-			return;
-	if (ap->index == 0) {
-		DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
-		if (awe_set_sample((awe_voice_list*)ap) == 0)
-			return;
-	}
-
-	/* calculate offset */
-	if (ap->fixkey >= 0) {
-		DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune));
-		offset = (ap->fixkey - ap->root) * 4096 / 12;
-	} else {
-		DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune));
-		offset = (vp->note - ap->root) * 4096 / 12;
-		DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
-	}
-	offset = (offset * ap->scaleTuning) / 100;
-	DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
-	offset += ap->tune * 4096 / 1200;
-	DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
-	if (cp->bender != 0) {
-		DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender));
-		/* (819200: 1 semitone) ==> (4096: 12 semitones) */
-		offset += cp->bender * cp->bender_range / 2400;
-	}
-
-	/* add initial pitch correction */
-	if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH))
-		offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH];
-	else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH))
-		offset += cp->fx.val[AWE_FX_INIT_PITCH];
-
-	/* 0xe000: root pitch */
-	vp->apitch = 0xe000 + ap->rate_offset + offset;
-	DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset));
-	if (vp->apitch > 0xffff)
-		vp->apitch = 0xffff;
-	if (vp->apitch < 0)
-		vp->apitch = 0;
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* calculate MIDI key and semitone from the specified frequency */
-static void
-awe_calc_pitch_from_freq(int voice, int freq)
-{
-	voice_info *vp = &voices[voice];
-	awe_voice_info *ap;
-	FX_Rec *fx = &voices[voice].cinfo->fx;
-	FX_Rec *fx_lay = NULL;
-	int offset;
-	int note;
-
-	if (voices[voice].layer < MAX_LAYERS)
-		fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
-	/* search voice information */
-	if ((ap = vp->sample) == NULL)
-		return;
-	if (ap->index == 0) {
-		DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
-		if (awe_set_sample((awe_voice_list*)ap) == 0)
-			return;
-	}
-	note = freq_to_note(freq);
-	offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200;
-	offset = (offset * ap->scaleTuning) / 100;
-	if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH))
-		offset += fx_lay->val[AWE_FX_INIT_PITCH];
-	else if (FX_ON(fx, AWE_FX_INIT_PITCH))
-		offset += fx->val[AWE_FX_INIT_PITCH];
-	vp->apitch = 0xe000 + ap->rate_offset + offset;
-	if (vp->apitch > 0xffff)
-		vp->apitch = 0xffff;
-	if (vp->apitch < 0)
-		vp->apitch = 0;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*
- * calculate volume attenuation
- *
- * Voice volume is controlled by volume attenuation parameter.
- * So volume becomes maximum when avol is 0 (no attenuation), and
- * minimum when 255 (-96dB or silence).
- */
-
-static int vol_table[128] = {
-	255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
-	47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
-	31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
-	22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
-	15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
-	10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
-	6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
-	2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
-};
-
-/* tables for volume->attenuation calculation */
-static unsigned char voltab1[128] = {
-   0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-   0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
-   0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
-   0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
-   0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
-   0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
-   0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
-   0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
-   0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
-   0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
-   0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
-   0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
-   0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char voltab2[128] = {
-   0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
-   0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
-   0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
-   0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
-   0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
-   0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
-   0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
-   0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
-   0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
-   0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
-   0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
-   0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
-   0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char expressiontab[128] = {
-   0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
-   0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
-   0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
-   0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
-   0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
-   0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
-   0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
-   0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
-   0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
-   0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
-   0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
-   0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
-   0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static void
-awe_calc_volume(int voice)
-{
-	voice_info *vp = &voices[voice];
-	awe_voice_info *ap;
-	awe_chan_info *cp = voices[voice].cinfo;
-	int vol;
-
-	/* search voice information */
-	if ((ap = vp->sample) == NULL)
-		return;
-
-	ap = vp->sample;
-	if (ap->index == 0) {
-		DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
-		if (awe_set_sample((awe_voice_list*)ap) == 0)
-			return;
-	}
-	
-	if (ctrls[AWE_MD_NEW_VOLUME_CALC]) {
-		int main_vol = cp->main_vol * ap->amplitude / 127;
-		limitvalue(vp->velocity, 0, 127);
-		limitvalue(main_vol, 0, 127);
-		limitvalue(cp->expression_vol, 0, 127);
-
-		vol = voltab1[main_vol] + voltab2[vp->velocity];
-		vol = (vol * 8) / 3;
-		vol += ap->attenuation;
-		if (cp->expression_vol < 127)
-			vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128;
-		vol += atten_offset;
-		if (atten_relative)
-			vol += ctrls[AWE_MD_ZERO_ATTEN];
-		limitvalue(vol, 0, 255);
-		vp->avol = vol;
-		
-	} else {
-		/* 0 - 127 */
-		vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127);
-		vol = vol * ap->amplitude / 127;
-
-		if (vol < 0) vol = 0;
-		if (vol > 127) vol = 127;
-
-		/* calc to attenuation */
-		vol = vol_table[vol];
-		vol += (int)ap->attenuation;
-		vol += atten_offset;
-		if (atten_relative)
-			vol += ctrls[AWE_MD_ZERO_ATTEN];
-		if (vol > 255) vol = 255;
-
-		vp->avol = vol;
-	}
-	if (cp->bank !=  AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) {
-		int atten;
-		if (vp->velocity < 70) atten = 70;
-		else atten = vp->velocity;
-		vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7;
-	} else {
-		vp->acutoff = ap->parm.cutoff;
-	}
-	DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));
-}
-
-/* change master volume */
-static void
-awe_change_master_volume(short val)
-{
-	limitvalue(val, 0, 127);
-	atten_offset = vol_table[val];
-	atten_relative = TRUE;
-	awe_update_volume();
-}
-
-/* update volumes of all available channels */
-static void awe_update_volume(void)
-{
-	int i;
-	for (i = 0; i < awe_max_voices; i++)
-		awe_set_voice_vol(i, TRUE);
-}
-
-/* set sostenuto on */
-static void awe_sostenuto_on(int voice, int forced)
-{
-	if (IS_NO_EFFECT(voice) && !forced) return;
-	voices[voice].sostenuto = 127;
-}
-
-
-/* drop sustain */
-static void awe_sustain_off(int voice, int forced)
-{
-	if (voices[voice].state == AWE_ST_SUSTAINED) {
-		awe_note_off(voice);
-		awe_fx_init(voices[voice].ch);
-		awe_voice_init(voice, FALSE);
-	}
-}
-
-
-/* terminate and initialize voice */
-static void awe_terminate_and_init(int voice, int forced)
-{
-	awe_terminate(voice);
-	awe_fx_init(voices[voice].ch);
-	awe_voice_init(voice, TRUE);
-}
-
-
-/*
- * synth operation routines
- */
-
-#define AWE_VOICE_KEY(v)	(0x8000 | (v))
-#define AWE_CHAN_KEY(c,n)	(((c) << 8) | ((n) + 1))
-#define KEY_CHAN_MATCH(key,c)	(((key) >> 8) == (c))
-
-/* initialize the voice */
-static void
-awe_voice_init(int voice, int init_all)
-{
-	voice_info *vp = &voices[voice];
-
-	/* reset voice search key */
-	if (playing_mode == AWE_PLAY_DIRECT)
-		vp->key = AWE_VOICE_KEY(voice);
-	else
-		vp->key = 0;
-
-	/* clear voice mapping */
-	voice_alloc->map[voice] = 0;
-
-	/* touch the timing flag */
-	vp->time = current_alloc_time;
-
-	/* initialize other parameters if necessary */
-	if (init_all) {
-		vp->note = -1;
-		vp->velocity = 0;
-		vp->sostenuto = 0;
-
-		vp->sample = NULL;
-		vp->cinfo = &channels[voice];
-		vp->ch = voice;
-		vp->state = AWE_ST_OFF;
-
-		/* emu8000 parameters */
-		vp->apitch = 0;
-		vp->avol = 255;
-		vp->apan = -1;
-	}
-}
-
-/* clear effects */
-static void awe_fx_init(int ch)
-{
-	if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) {
-		memset(&channels[ch].fx, 0, sizeof(channels[ch].fx));
-		memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer));
-	}
-}
-
-/* initialize channel info */
-static void awe_channel_init(int ch, int init_all)
-{
-	awe_chan_info *cp = &channels[ch];
-	cp->channel = ch;
-	if (init_all) {
-		cp->panning = 0; /* zero center */
-		cp->bender_range = 200; /* sense * 100 */
-		cp->main_vol = 127;
-		if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) {
-			cp->instr = ctrls[AWE_MD_DEF_DRUM];
-			cp->bank = AWE_DRUM_BANK;
-		} else {
-			cp->instr = ctrls[AWE_MD_DEF_PRESET];
-			cp->bank = ctrls[AWE_MD_DEF_BANK];
-		}
-	}
-
-	cp->bender = 0; /* zero tune skew */
-	cp->expression_vol = 127;
-	cp->chan_press = 0;
-	cp->sustained = 0;
-
-	if (! ctrls[AWE_MD_KEEP_EFFECT]) {
-		memset(&cp->fx, 0, sizeof(cp->fx));
-		memset(&cp->fx_layer, 0, sizeof(cp->fx_layer));
-	}
-}
-
-
-/* change the voice parameters; voice = channel */
-static void awe_voice_change(int voice, fx_affect_func func)
-{
-	int i; 
-	switch (playing_mode) {
-	case AWE_PLAY_DIRECT:
-		func(voice, FALSE);
-		break;
-	case AWE_PLAY_INDIRECT:
-		for (i = 0; i < awe_max_voices; i++)
-			if (voices[i].key == AWE_VOICE_KEY(voice))
-				func(i, FALSE);
-		break;
-	default:
-		for (i = 0; i < awe_max_voices; i++)
-			if (KEY_CHAN_MATCH(voices[i].key, voice))
-				func(i, FALSE);
-		break;
-	}
-}
-
-
-/*
- * device open / close
- */
-
-/* open device:
- *   reset status of all voices, and clear sample position flag
- */
-static int
-awe_open(int dev, int mode)
-{
-	if (awe_busy)
-		return -EBUSY;
-
-	awe_busy = TRUE;
-
-	/* set default mode */
-	awe_init_ctrl_parms(FALSE);
-	atten_relative = TRUE;
-	atten_offset = 0;
-	drum_flags = DEFAULT_DRUM_FLAGS;
-	playing_mode = AWE_PLAY_INDIRECT;
-
-	/* reset voices & channels */
-	awe_reset(dev);
-
-	patch_opened = 0;
-
-	return 0;
-}
-
-
-/* close device:
- *   reset all voices again (terminate sounds)
- */
-static void
-awe_close(int dev)
-{
-	awe_reset(dev);
-	awe_busy = FALSE;
-}
-
-
-/* set miscellaneous mode parameters
- */
-static void
-awe_init_ctrl_parms(int init_all)
-{
-	int i;
-	for (i = 0; i < AWE_MD_END; i++) {
-		if (init_all || ctrl_parms[i].init_each_time)
-			ctrls[i] = ctrl_parms[i].value;
-	}
-}
-
-
-/* sequencer I/O control:
- */
-static int
-awe_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
-	switch (cmd) {
-	case SNDCTL_SYNTH_INFO:
-		if (playing_mode == AWE_PLAY_DIRECT)
-			awe_info.nr_voices = awe_max_voices;
-		else
-			awe_info.nr_voices = AWE_MAX_CHANNELS;
-		if (copy_to_user(arg, &awe_info, sizeof(awe_info)))
-			return -EFAULT;
-		return 0;
-		break;
-
-	case SNDCTL_SEQ_RESETSAMPLES:
-		awe_reset(dev);
-		awe_reset_samples();
-		return 0;
-		break;
-
-	case SNDCTL_SEQ_PERCMODE:
-		/* what's this? */
-		return 0;
-		break;
-
-	case SNDCTL_SYNTH_MEMAVL:
-		return memsize - awe_free_mem_ptr() * 2;
-		break;
-
-	default:
-		printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd);
-		return -EINVAL;
-		break;
-	}
-}
-
-
-static int voice_in_range(int voice)
-{
-	if (playing_mode == AWE_PLAY_DIRECT) {
-		if (voice < 0 || voice >= awe_max_voices)
-			return FALSE;
-	} else {
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return FALSE;
-	}
-	return TRUE;
-}
-
-static void release_voice(int voice, int do_sustain)
-{
-	if (IS_NO_SOUND(voice))
-		return;
-	if (do_sustain && (voices[voice].cinfo->sustained == 127 ||
-			    voices[voice].sostenuto == 127))
-		voices[voice].state = AWE_ST_SUSTAINED;
-	else {
-		awe_note_off(voice);
-		awe_fx_init(voices[voice].ch);
-		awe_voice_init(voice, FALSE);
-	}
-}
-
-/* release all notes */
-static void awe_note_off_all(int do_sustain)
-{
-	int i;
-	for (i = 0; i < awe_max_voices; i++)
-		release_voice(i, do_sustain);
-}
-
-/* kill a voice:
- *   not terminate, just release the voice.
- */
-static int
-awe_kill_note(int dev, int voice, int note, int velocity)
-{
-	int i, v2, key;
-
-	DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity));
-	if (! voice_in_range(voice))
-		return -EINVAL;
-
-	switch (playing_mode) {
-	case AWE_PLAY_DIRECT:
-	case AWE_PLAY_INDIRECT:
-		key = AWE_VOICE_KEY(voice);
-		break;
-
-	case AWE_PLAY_MULTI2:
-		v2 = voice_alloc->map[voice] >> 8;
-		voice_alloc->map[voice] = 0;
-		voice = v2;
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return -EINVAL;
-		/* continue to below */
-	default:
-		key = AWE_CHAN_KEY(voice, note);
-		break;
-	}
-
-	for (i = 0; i < awe_max_voices; i++) {
-		if (voices[i].key == key)
-			release_voice(i, TRUE);
-	}
-	return 0;
-}
-
-
-static void start_or_volume_change(int voice, int velocity)
-{
-	voices[voice].velocity = velocity;
-	awe_calc_volume(voice);
-	if (voices[voice].state == AWE_ST_STANDBY)
-		awe_note_on(voice);
-	else if (voices[voice].state == AWE_ST_ON)
-		awe_set_volume(voice, FALSE);
-}
-
-static void set_and_start_voice(int voice, int state)
-{
-	/* calculate pitch & volume parameters */
-	voices[voice].state = state;
-	awe_calc_pitch(voice);
-	awe_calc_volume(voice);
-	if (state == AWE_ST_ON)
-		awe_note_on(voice);
-}
-
-/* start a voice:
- *   if note is 255, identical with aftertouch function.
- *   Otherwise, start a voice with specified not and volume.
- */
-static int
-awe_start_note(int dev, int voice, int note, int velocity)
-{
-	int i, key, state, volonly;
-
-	DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity));
-	if (! voice_in_range(voice))
-		return -EINVAL;
-	    
-	if (velocity == 0)
-		state = AWE_ST_STANDBY; /* stand by for playing */
-	else
-		state = AWE_ST_ON;	/* really play */
-	volonly = FALSE;
-
-	switch (playing_mode) {
-	case AWE_PLAY_DIRECT:
-	case AWE_PLAY_INDIRECT:
-		key = AWE_VOICE_KEY(voice);
-		if (note == 255)
-			volonly = TRUE;
-		break;
-
-	case AWE_PLAY_MULTI2:
-		voice = voice_alloc->map[voice] >> 8;
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return -EINVAL;
-		/* continue to below */
-	default:
-		if (note >= 128) { /* key volume mode */
-			note -= 128;
-			volonly = TRUE;
-		}
-		key = AWE_CHAN_KEY(voice, note);
-		break;
-	}
-
-	/* dynamic volume change */
-	if (volonly) {
-		for (i = 0; i < awe_max_voices; i++) {
-			if (voices[i].key == key)
-				start_or_volume_change(i, velocity);
-		}
-		return 0;
-	}
-
-	/* if the same note still playing, stop it */
-	if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) {
-		for (i = 0; i < awe_max_voices; i++)
-			if (voices[i].key == key) {
-				if (voices[i].state == AWE_ST_ON) {
-					awe_note_off(i);
-					awe_voice_init(i, FALSE);
-				} else if (voices[i].state == AWE_ST_STANDBY)
-					awe_voice_init(i, TRUE);
-			}
-	}
-
-	/* allocate voices */
-	if (playing_mode == AWE_PLAY_DIRECT)
-		awe_alloc_one_voice(voice, note, velocity);
-	else
-		awe_alloc_multi_voices(voice, note, velocity, key);
-
-	/* turn off other voices exlusively (for drums) */
-	for (i = 0; i < awe_max_voices; i++)
-		if (voices[i].key == key)
-			awe_exclusive_off(i);
-
-	/* set up pitch and volume parameters */
-	for (i = 0; i < awe_max_voices; i++) {
-		if (voices[i].key == key && voices[i].state == AWE_ST_OFF)
-			set_and_start_voice(i, state);
-	}
-
-	return 0;
-}
-
-
-/* calculate hash key */
-static int
-awe_search_key(int bank, int preset, int note)
-{
-	unsigned int key;
-
-#if 1 /* new hash table */
-	if (bank == AWE_DRUM_BANK)
-		key = preset + note + 128;
-	else
-		key = bank + preset;
-#else
-	key = preset;
-#endif
-	key %= AWE_MAX_PRESETS;
-
-	return (int)key;
-}
-
-
-/* search instrument from hash table */
-static awe_voice_list *
-awe_search_instr(int bank, int preset, int note)
-{
-	awe_voice_list *p;
-	int key, key2;
-
-	key = awe_search_key(bank, preset, note);
-	for (p = preset_table[key]; p; p = p->next_bank) {
-		if (p->instr == preset && p->bank == bank)
-			return p;
-	}
-	key2 = awe_search_key(bank, preset, 0); /* search default */
-	if (key == key2)
-		return NULL;
-	for (p = preset_table[key2]; p; p = p->next_bank) {
-		if (p->instr == preset && p->bank == bank)
-			return p;
-	}
-	return NULL;
-}
-
-
-/* assign the instrument to a voice */
-static int
-awe_set_instr_2(int dev, int voice, int instr_no)
-{
-	if (playing_mode == AWE_PLAY_MULTI2) {
-		voice = voice_alloc->map[voice] >> 8;
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return -EINVAL;
-	}
-	return awe_set_instr(dev, voice, instr_no);
-}
-
-/* assign the instrument to a channel; voice is the channel number */
-static int
-awe_set_instr(int dev, int voice, int instr_no)
-{
-	awe_chan_info *cinfo;
-
-	if (! voice_in_range(voice))
-		return -EINVAL;
-
-	if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
-		return -EINVAL;
-
-	cinfo = &channels[voice];
-	cinfo->instr = instr_no;
-	DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no));
-
-	return 0;
-}
-
-
-/* reset all voices; terminate sounds and initialize parameters */
-static void
-awe_reset(int dev)
-{
-	int i;
-	current_alloc_time = 0;
-	/* don't turn off voice 31 and 32.  they are used also for FM voices */
-	for (i = 0; i < awe_max_voices; i++) {
-		awe_terminate(i);
-		awe_voice_init(i, TRUE);
-	}
-	for (i = 0; i < AWE_MAX_CHANNELS; i++)
-		awe_channel_init(i, TRUE);
-	for (i = 0; i < 16; i++) {
-		awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127;
-		awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127;
-	}
-	awe_init_fm();
-	awe_tweak();
-}
-
-
-/* hardware specific control:
- *   GUS specific and AWE32 specific controls are available.
- */
-static void
-awe_hw_control(int dev, unsigned char *event)
-{
-	int cmd = event[2];
-	if (cmd & _AWE_MODE_FLAG)
-		awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-	else
-		awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#endif
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* GUS compatible controls */
-static void
-awe_hw_gus_control(int dev, int cmd, unsigned char *event)
-{
-	int voice, i, key;
-	unsigned short p1;
-	short p2;
-	int plong;
-
-	if (MULTI_LAYER_MODE())
-		return;
-	if (cmd == _GUS_NUMVOICES)
-		return;
-
-	voice = event[3];
-	if (! voice_in_range(voice))
-		return;
-
-	p1 = *(unsigned short *) &event[4];
-	p2 = *(short *) &event[6];
-	plong = *(int*) &event[4];
-
-	switch (cmd) {
-	case _GUS_VOICESAMPLE:
-		awe_set_instr(dev, voice, p1);
-		return;
-
-	case _GUS_VOICEBALA:
-		/* 0 to 15 --> -128 to 127 */
-		awe_panning(dev, voice, ((int)p1 << 4) - 128);
-		return;
-
-	case _GUS_VOICEVOL:
-	case _GUS_VOICEVOL2:
-		/* not supported yet */
-		return;
-
-	case _GUS_RAMPRANGE:
-	case _GUS_RAMPRATE:
-	case _GUS_RAMPMODE:
-	case _GUS_RAMPON:
-	case _GUS_RAMPOFF:
-		/* volume ramping not supported */
-		return;
-
-	case _GUS_VOLUME_SCALE:
-		return;
-
-	case _GUS_VOICE_POS:
-		FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START,
-		       (short)(plong & 0x7fff));
-		FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START,
-		       (plong >> 15) & 0xffff);
-		return;
-	}
-
-	key = AWE_VOICE_KEY(voice);
-	for (i = 0; i < awe_max_voices; i++) {
-		if (voices[i].key == key) {
-			switch (cmd) {
-			case _GUS_VOICEON:
-				awe_note_on(i);
-				break;
-
-			case _GUS_VOICEOFF:
-				awe_terminate(i);
-				awe_fx_init(voices[i].ch);
-				awe_voice_init(i, TRUE);
-				break;
-
-			case _GUS_VOICEFADE:
-				awe_note_off(i);
-				awe_fx_init(voices[i].ch);
-				awe_voice_init(i, FALSE);
-				break;
-
-			case _GUS_VOICEFREQ:
-				awe_calc_pitch_from_freq(i, plong);
-				break;
-			}
-		}
-	}
-}
-
-#endif /* gus_compat */
-
-
-/* AWE32 specific controls */
-static void
-awe_hw_awe_control(int dev, int cmd, unsigned char *event)
-{
-	int voice;
-	unsigned short p1;
-	short p2;
-	int i;
-
-	voice = event[3];
-	if (! voice_in_range(voice))
-		return;
-
-	if (playing_mode == AWE_PLAY_MULTI2) {
-		voice = voice_alloc->map[voice] >> 8;
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return;
-	}
-
-	p1 = *(unsigned short *) &event[4];
-	p2 = *(short *) &event[6];
-
-	switch (cmd) {
-	case _AWE_DEBUG_MODE:
-		ctrls[AWE_MD_DEBUG_MODE] = p1;
-		printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
-		break;
-	case _AWE_REVERB_MODE:
-		ctrls[AWE_MD_REVERB_MODE] = p1;
-		awe_update_reverb_mode();
-		break;
-
-	case _AWE_CHORUS_MODE:
-		ctrls[AWE_MD_CHORUS_MODE] = p1;
-		awe_update_chorus_mode();
-		break;
-		      
-	case _AWE_REMOVE_LAST_SAMPLES:
-		DEBUG(0,printk("AWE32: remove last samples\n"));
-		awe_reset(0);
-		if (locked_sf_id > 0)
-			awe_remove_samples(locked_sf_id);
-		break;
-
-	case _AWE_INITIALIZE_CHIP:
-		awe_initialize();
-		break;
-
-	case _AWE_SEND_EFFECT:
-		i = -1;
-		if (p1 >= 0x100) {
-			i = (p1 >> 8);
-			if (i < 0 || i >= MAX_LAYERS)
-				break;
-		}
-		awe_send_effect(voice, i, p1, p2);
-		break;
-
-	case _AWE_RESET_CHANNEL:
-		awe_channel_init(voice, !p1);
-		break;
-		
-	case _AWE_TERMINATE_ALL:
-		awe_reset(0);
-		break;
-
-	case _AWE_TERMINATE_CHANNEL:
-		awe_voice_change(voice, awe_terminate_and_init);
-		break;
-
-	case _AWE_RELEASE_ALL:
-		awe_note_off_all(FALSE);
-		break;
-	case _AWE_NOTEOFF_ALL:
-		awe_note_off_all(TRUE);
-		break;
-
-	case _AWE_INITIAL_VOLUME:
-		DEBUG(0,printk("AWE32: init attenuation %d\n", p1));
-		atten_relative = (char)p2;
-		atten_offset = (short)p1;
-		awe_update_volume();
-		break;
-
-	case _AWE_CHN_PRESSURE:
-		channels[voice].chan_press = p1;
-		awe_modwheel_change(voice, p1);
-		break;
-
-	case _AWE_CHANNEL_MODE:
-		DEBUG(0,printk("AWE32: channel mode = %d\n", p1));
-		playing_mode = p1;
-		awe_reset(0);
-		break;
-
-	case _AWE_DRUM_CHANNELS:
-		DEBUG(0,printk("AWE32: drum flags = %x\n", p1));
-		drum_flags = *(unsigned int*)&event[4];
-		break;
-
-	case _AWE_MISC_MODE:
-		DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2));
-		if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) {
-			ctrls[p1] = p2;
-			if (ctrl_parms[p1].update)
-				ctrl_parms[p1].update();
-		}
-		break;
-
-	case _AWE_EQUALIZER:
-		ctrls[AWE_MD_BASS_LEVEL] = p1;
-		ctrls[AWE_MD_TREBLE_LEVEL] = p2;
-		awe_update_equalizer();
-		break;
-
-	default:
-		DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice));
-		break;
-	}
-}
-
-
-/* change effects */
-static void
-awe_send_effect(int voice, int layer, int type, int val)
-{
-	awe_chan_info *cinfo;
-	FX_Rec *fx;
-	int mode;
-
-	cinfo = &channels[voice];
-	if (layer >= 0 && layer < MAX_LAYERS)
-		fx = &cinfo->fx_layer[layer];
-	else
-		fx = &cinfo->fx;
-
-	if (type & 0x40)
-		mode = FX_FLAG_OFF;
-	else if (type & 0x80)
-		mode = FX_FLAG_ADD;
-	else
-		mode = FX_FLAG_SET;
-	type &= 0x3f;
-
-	if (type >= 0 && type < AWE_FX_END) {
-		DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val));
-		if (mode == FX_FLAG_SET)
-			FX_SET(fx, type, val);
-		else if (mode == FX_FLAG_ADD)
-			FX_ADD(fx, type, val);
-		else
-			FX_UNSET(fx, type);
-		if (mode != FX_FLAG_OFF && parm_defs[type].realtime) {
-			DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice));
-			awe_voice_change(voice, parm_defs[type].realtime);
-		}
-	}
-}
-
-
-/* change modulation wheel; voice is already mapped on multi2 mode */
-static void
-awe_modwheel_change(int voice, int value)
-{
-	int i;
-	awe_chan_info *cinfo;
-
-	cinfo = &channels[voice];
-	i = value * ctrls[AWE_MD_MOD_SENSE] / 1200;
-	FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i);
-	awe_voice_change(voice, awe_fx_fmmod);
-	FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i);
-	awe_voice_change(voice, awe_fx_fm2frq2);
-}
-
-
-/* voice pressure change */
-static void
-awe_aftertouch(int dev, int voice, int pressure)
-{
-	int note;
-
-	DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure));
-	if (! voice_in_range(voice))
-		return;
-
-	switch (playing_mode) {
-	case AWE_PLAY_DIRECT:
-	case AWE_PLAY_INDIRECT:
-		awe_start_note(dev, voice, 255, pressure);
-		break;
-	case AWE_PLAY_MULTI2:
-		note = (voice_alloc->map[voice] & 0xff) - 1;
-		awe_key_pressure(dev, voice, note + 0x80, pressure);
-		break;
-	}
-}
-
-
-/* voice control change */
-static void
-awe_controller(int dev, int voice, int ctrl_num, int value)
-{
-	awe_chan_info *cinfo;
-
-	if (! voice_in_range(voice))
-		return;
-
-	if (playing_mode == AWE_PLAY_MULTI2) {
-		voice = voice_alloc->map[voice] >> 8;
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return;
-	}
-
-	cinfo = &channels[voice];
-
-	switch (ctrl_num) {
-	case CTL_BANK_SELECT: /* MIDI control #0 */
-		DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
-		if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
-		    !ctrls[AWE_MD_TOGGLE_DRUM_BANK])
-			break;
-		if (value < 0 || value > 255)
-			break;
-		cinfo->bank = value;
-		if (cinfo->bank == AWE_DRUM_BANK)
-			DRUM_CHANNEL_ON(cinfo->channel);
-		else
-			DRUM_CHANNEL_OFF(cinfo->channel);
-		awe_set_instr(dev, voice, cinfo->instr);
-		break;
-
-	case CTL_MODWHEEL: /* MIDI control #1 */
-		DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value));
-		awe_modwheel_change(voice, value);
-		break;
-
-	case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */
-		DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value));
-		/* zero centered */
-		cinfo->bender = value;
-		awe_voice_change(voice, awe_set_voice_pitch);
-		break;
-
-	case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */
-		DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value));
-		/* value = sense x 100 */
-		cinfo->bender_range = value;
-		/* no audible pitch change yet.. */
-		break;
-
-	case CTL_EXPRESSION: /* MIDI control #11 */
-		if (SINGLE_LAYER_MODE())
-			value /= 128;
-	case CTRL_EXPRESSION: /* SEQ1 V2 control */
-		DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value));
-		/* 0 - 127 */
-		cinfo->expression_vol = value;
-		awe_voice_change(voice, awe_set_voice_vol);
-		break;
-
-	case CTL_PAN:	/* MIDI control #10 */
-		DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value));
-		/* (0-127) -> signed 8bit */
-		cinfo->panning = value * 2 - 128;
-		if (ctrls[AWE_MD_REALTIME_PAN])
-			awe_voice_change(voice, awe_set_pan);
-		break;
-
-	case CTL_MAIN_VOLUME:	/* MIDI control #7 */
-		if (SINGLE_LAYER_MODE())
-			value = (value * 100) / 16383;
-	case CTRL_MAIN_VOLUME:	/* SEQ1 V2 control */
-		DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value));
-		/* 0 - 127 */
-		cinfo->main_vol = value;
-		awe_voice_change(voice, awe_set_voice_vol);
-		break;
-
-	case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */
-		DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value));
-		FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2);
-		break;
-
-	case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */
-		DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value));
-		FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2);
-		break;
-
-	case 120:  /* all sounds off */
-		awe_note_off_all(FALSE);
-		break;
-	case 123:  /* all notes off */
-		awe_note_off_all(TRUE);
-		break;
-
-	case CTL_SUSTAIN: /* MIDI control #64 */
-		cinfo->sustained = value;
-		if (value != 127)
-			awe_voice_change(voice, awe_sustain_off);
-		break;
-
-	case CTL_SOSTENUTO: /* MIDI control #66 */
-		if (value == 127)
-			awe_voice_change(voice, awe_sostenuto_on);
-		else
-			awe_voice_change(voice, awe_sustain_off);
-		break;
-
-	default:
-		DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n",
-			   voice, ctrl_num, value));
-		break;
-	}
-}
-
-
-/* voice pan change (value = -128 - 127) */
-static void
-awe_panning(int dev, int voice, int value)
-{
-	awe_chan_info *cinfo;
-
-	if (! voice_in_range(voice))
-		return;
-
-	if (playing_mode == AWE_PLAY_MULTI2) {
-		voice = voice_alloc->map[voice] >> 8;
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return;
-	}
-
-	cinfo = &channels[voice];
-	cinfo->panning = value;
-	DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning));
-	if (ctrls[AWE_MD_REALTIME_PAN])
-		awe_voice_change(voice, awe_set_pan);
-}
-
-
-/* volume mode change */
-static void
-awe_volume_method(int dev, int mode)
-{
-	/* not impremented */
-	DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode));
-}
-
-
-/* pitch wheel change: 0-16384 */
-static void
-awe_bender(int dev, int voice, int value)
-{
-	awe_chan_info *cinfo;
-
-	if (! voice_in_range(voice))
-		return;
-
-	if (playing_mode == AWE_PLAY_MULTI2) {
-		voice = voice_alloc->map[voice] >> 8;
-		if (voice < 0 || voice >= AWE_MAX_CHANNELS)
-			return;
-	}
-
-	/* convert to zero centered value */
-	cinfo = &channels[voice];
-	cinfo->bender = value - 8192;
-	DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender));
-	awe_voice_change(voice, awe_set_voice_pitch);
-}
-
-
-/*
- * load a sound patch:
- *   three types of patches are accepted: AWE, GUS, and SYSEX.
- */
-
-static int
-awe_load_patch(int dev, int format, const char __user *addr,
-	       int offs, int count, int pmgr_flag)
-{
-	awe_patch_info patch;
-	int rc = 0;
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-	if (format == GUS_PATCH) {
-		return awe_load_guspatch(addr, offs, count, pmgr_flag);
-	} else
-#endif
-	if (format == SYSEX_PATCH) {
-		/* no system exclusive message supported yet */
-		return 0;
-	} else if (format != AWE_PATCH) {
-		printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format);
-		return -EINVAL;
-	}
-	
-	if (count < AWE_PATCH_INFO_SIZE) {
-		printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
-		return -EINVAL;
-	}
-	if (copy_from_user(((char*)&patch) + offs, addr + offs, 
-			   AWE_PATCH_INFO_SIZE - offs))
-		return -EFAULT;
-
-	count -= AWE_PATCH_INFO_SIZE;
-	if (count < patch.len) {
-		printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n",
-		       count, patch.len);
-		return -EINVAL;
-	}
-	
-	switch (patch.type) {
-	case AWE_LOAD_INFO:
-		rc = awe_load_info(&patch, addr, count);
-		break;
-	case AWE_LOAD_DATA:
-		rc = awe_load_data(&patch, addr, count);
-		break;
-	case AWE_OPEN_PATCH:
-		rc = awe_open_patch(&patch, addr, count);
-		break;
-	case AWE_CLOSE_PATCH:
-		rc = awe_close_patch(&patch, addr, count);
-		break;
-	case AWE_UNLOAD_PATCH:
-		rc = awe_unload_patch(&patch, addr, count);
-		break;
-	case AWE_REPLACE_DATA:
-		rc = awe_replace_data(&patch, addr, count);
-		break;
-	case AWE_MAP_PRESET:
-		rc = awe_load_map(&patch, addr, count);
-		break;
-	/* case AWE_PROBE_INFO:
-		rc = awe_probe_info(&patch, addr, count);
-		break;*/
-	case AWE_PROBE_DATA:
-		rc = awe_probe_data(&patch, addr, count);
-		break;
-	case AWE_REMOVE_INFO:
-		rc = awe_remove_info(&patch, addr, count);
-		break;
-	case AWE_LOAD_CHORUS_FX:
-		rc = awe_load_chorus_fx(&patch, addr, count);
-		break;
-	case AWE_LOAD_REVERB_FX:
-		rc = awe_load_reverb_fx(&patch, addr, count);
-		break;
-
-	default:
-		printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n",
-		       patch.type);
-		rc = -EINVAL;
-	}
-
-	return rc;
-}
-
-
-/* create an sf list record */
-static int
-awe_create_sf(int type, char *name)
-{
-	sf_list *rec;
-
-	/* terminate sounds */
-	awe_reset(0);
-	rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL);
-	if (rec == NULL)
-		return 1; /* no memory */
-	rec->sf_id = current_sf_id + 1;
-	rec->type = type;
-	if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0)
-		locked_sf_id = current_sf_id + 1;
-	rec->num_info = awe_free_info();
-	rec->num_sample = awe_free_sample();
-	rec->mem_ptr = awe_free_mem_ptr();
-	rec->infos = rec->last_infos = NULL;
-	rec->samples = rec->last_samples = NULL;
-
-	/* add to linked-list */
-	rec->next = NULL;
-	rec->prev = sftail;
-	if (sftail)
-		sftail->next = rec;
-	else
-		sfhead = rec;
-	sftail = rec;
-	current_sf_id++;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-	rec->shared = NULL;
-	if (name)
-		memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
-	else
-		strcpy(rec->name, "*TEMPORARY*");
-	if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) {
-		/* is the current font really a shared font? */
-		if (is_shared_sf(rec->name)) {
-			/* check if the shared font is already installed */
-			sf_list *p;
-			for (p = rec->prev; p; p = p->prev) {
-				if (is_identical_name(rec->name, p)) {
-					rec->shared = p;
-					break;
-				}
-			}
-		}
-	}
-#endif /* allow sharing */
-
-	return 0;
-}
-
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-
-/* check if the given name is a valid shared name */
-#define ASC_TO_KEY(c) ((c) - 'A' + 1)
-static int is_shared_sf(unsigned char *name)
-{
-	static unsigned char id_head[4] = {
-		ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
-		AWE_MAJOR_VERSION,
-	};
-	if (memcmp(name, id_head, 4) == 0)
-		return TRUE;
-	return FALSE;
-}
-
-/* check if the given name matches to the existing list */
-static int is_identical_name(unsigned char *name, sf_list *p) 
-{
-	char *id = p->name;
-	if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
-		return TRUE;
-	return FALSE;
-}
-
-/* check if the given voice info exists */
-static int info_duplicated(sf_list *sf, awe_voice_list *rec)
-{
-	/* search for all sharing lists */
-	for (; sf; sf = sf->shared) {
-		awe_voice_list *p;
-		for (p = sf->infos; p; p = p->next) {
-			if (p->type == V_ST_NORMAL &&
-			    p->bank == rec->bank &&
-			    p->instr == rec->instr &&
-			    p->v.low == rec->v.low &&
-			    p->v.high == rec->v.high &&
-			    p->v.sample == rec->v.sample)
-				return TRUE;
-		}
-	}
-	return FALSE;
-}
-
-#endif /* AWE_ALLOW_SAMPLE_SHARING */
-
-
-/* free sf_list record */
-/* linked-list in this function is not cared */
-static void
-awe_free_sf(sf_list *sf)
-{
-	if (sf->infos) {
-		awe_voice_list *p, *next;
-		for (p = sf->infos; p; p = next) {
-			next = p->next;
-			kfree(p);
-		}
-	}
-	if (sf->samples) {
-		awe_sample_list *p, *next;
-		for (p = sf->samples; p; p = next) {
-			next = p->next;
-			kfree(p);
-		}
-	}
-	kfree(sf);
-}
-
-
-/* open patch; create sf list and set opened flag */
-static int
-awe_open_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
-	awe_open_parm parm;
-	int shared;
-
-	if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm)))
-		return -EFAULT;
-	shared = FALSE;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-	if (sftail && (parm.type & AWE_PAT_SHARED) != 0) {
-		/* is the previous font the same font? */
-		if (is_identical_name(parm.name, sftail)) {
-			/* then append to the previous */
-			shared = TRUE;
-			awe_reset(0);
-			if (parm.type & AWE_PAT_LOCKED)
-				locked_sf_id = current_sf_id;
-		}
-	}
-#endif /* allow sharing */
-	if (! shared) {
-		if (awe_create_sf(parm.type, parm.name)) {
-			printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n");
-			return -ENOMEM;
-		}
-	}
-	patch_opened = TRUE;
-	return current_sf_id;
-}
-
-/* check if the patch is already opened */
-static sf_list *
-check_patch_opened(int type, char *name)
-{
-	if (! patch_opened) {
-		if (awe_create_sf(type, name)) {
-			printk(KERN_ERR "AWE32: failed to alloc new list\n");
-			return NULL;
-		}
-		patch_opened = TRUE;
-		return sftail;
-	}
-	return sftail;
-}
-
-/* close the patch; if no voice is loaded, remove the patch */
-static int
-awe_close_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
-	if (patch_opened && sftail) {
-		/* if no voice is loaded, release the current patch */
-		if (sftail->infos == NULL) {
-			awe_reset(0);
-			awe_remove_samples(current_sf_id - 1);
-		}
-	}
-	patch_opened = 0;
-	return 0;
-}
-
-
-/* remove the latest patch */
-static int
-awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
-	if (current_sf_id > 0 && current_sf_id > locked_sf_id) {
-		awe_reset(0);
-		awe_remove_samples(current_sf_id - 1);
-	}
-	return 0;
-}
-
-/* allocate voice info list records */
-static awe_voice_list *
-alloc_new_info(void)
-{
-	awe_voice_list *newlist;
-	
-	newlist = kmalloc(sizeof(*newlist), GFP_KERNEL);
-	if (newlist == NULL) {
-		printk(KERN_ERR "AWE32: can't alloc info table\n");
-		return NULL;
-	}
-	return newlist;
-}
-
-/* allocate sample info list records */
-static awe_sample_list *
-alloc_new_sample(void)
-{
-	awe_sample_list *newlist;
-	
-	newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
-	if (newlist == NULL) {
-		printk(KERN_ERR "AWE32: can't alloc sample table\n");
-		return NULL;
-	}
-	return newlist;
-}
-
-/* load voice map */
-static int
-awe_load_map(awe_patch_info *patch, const char __user *addr, int count)
-{
-	awe_voice_map map;
-	awe_voice_list *rec, *p;
-	sf_list *sf;
-
-	/* get the link info */
-	if (count < sizeof(map)) {
-		printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
-		return -EINVAL;
-	}
-	if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
-		return -EFAULT;
-	
-	/* check if the identical mapping already exists */
-	p = awe_search_instr(map.map_bank, map.map_instr, map.map_key);
-	for (; p; p = p->next_instr) {
-		if (p->type == V_ST_MAPPED &&
-		    p->v.start == map.src_instr &&
-		    p->v.end == map.src_bank &&
-		    p->v.fixkey == map.src_key)
-			return 0; /* already present! */
-	}
-
-	if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL)
-		return -ENOMEM;
-
-	if ((rec = alloc_new_info()) == NULL)
-		return -ENOMEM;
-
-	rec->bank = map.map_bank;
-	rec->instr = map.map_instr;
-	rec->type = V_ST_MAPPED;
-	rec->disabled = FALSE;
-	awe_init_voice_info(&rec->v);
-	if (map.map_key >= 0) {
-		rec->v.low = map.map_key;
-		rec->v.high = map.map_key;
-	}
-	rec->v.start = map.src_instr;
-	rec->v.end = map.src_bank;
-	rec->v.fixkey = map.src_key;
-	add_sf_info(sf, rec);
-	add_info_list(rec);
-
-	return 0;
-}
-
-#if 0
-/* probe preset in the current list -- nothing to be loaded */
-static int
-awe_probe_info(awe_patch_info *patch, const char __user *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-	awe_voice_map map;
-	awe_voice_list *p;
-
-	if (! patch_opened)
-		return -EINVAL;
-
-	/* get the link info */
-	if (count < sizeof(map)) {
-		printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
-		return -EINVAL;
-	}
-	if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
-		return -EFAULT;
-	
-	/* check if the identical mapping already exists */
-	if (sftail == NULL)
-		return -EINVAL;
-	p = awe_search_instr(map.src_bank, map.src_instr, map.src_key);
-	for (; p; p = p->next_instr) {
-		if (p->type == V_ST_NORMAL &&
-		    is_identical_holder(p->holder, sftail) &&
-		    p->v.low <= map.src_key &&
-		    p->v.high >= map.src_key)
-			return 0; /* already present! */
-	}
-#endif /* allow sharing */
-	return -EINVAL;
-}
-#endif
-
-/* probe sample in the current list -- nothing to be loaded */
-static int
-awe_probe_data(awe_patch_info *patch, const char __user *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-	if (! patch_opened)
-		return -EINVAL;
-
-	/* search the specified sample by optarg */
-	if (search_sample_index(sftail, patch->optarg) != NULL)
-		return 0;
-#endif /* allow sharing */
-	return -EINVAL;
-}
-
-		
-/* remove the present instrument layers */
-static int
-remove_info(sf_list *sf, int bank, int instr)
-{
-	awe_voice_list *prev, *next, *p;
-	int removed = 0;
-
-	prev = NULL;
-	for (p = sf->infos; p; p = next) {
-		next = p->next;
-		if (p->type == V_ST_NORMAL &&
-		    p->bank == bank && p->instr == instr) {
-			/* remove this layer */
-			if (prev)
-				prev->next = next;
-			else
-				sf->infos = next;
-			if (p == sf->last_infos)
-				sf->last_infos = prev;
-			sf->num_info--;
-			removed++;
-			kfree(p);
-		} else
-			prev = p;
-	}
-	if (removed)
-		rebuild_preset_list();
-	return removed;
-}
-
-/* load voice information data */
-static int
-awe_load_info(awe_patch_info *patch, const char __user *addr, int count)
-{
-	int offset;
-	awe_voice_rec_hdr hdr;
-	int i;
-	int total_size;
-	sf_list *sf;
-	awe_voice_list *rec;
-
-	if (count < AWE_VOICE_REC_SIZE) {
-		printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
-		return -EINVAL;
-	}
-
-	offset = AWE_PATCH_INFO_SIZE;
-	if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE))
-		return -EFAULT;
-	offset += AWE_VOICE_REC_SIZE;
-
-	if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
-		printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices);
-		return -EINVAL;
-	}
-	total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
-	if (count < total_size) {
-		printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
-		       count, hdr.nvoices);
-		return -EINVAL;
-	}
-
-	if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
-		return -ENOMEM;
-
-	switch (hdr.write_mode) {
-	case AWE_WR_EXCLUSIVE:
-		/* exclusive mode - if the instrument already exists,
-		   return error */
-		for (rec = sf->infos; rec; rec = rec->next) {
-			if (rec->type == V_ST_NORMAL &&
-			    rec->bank == hdr.bank &&
-			    rec->instr == hdr.instr)
-				return -EINVAL;
-		}
-		break;
-	case AWE_WR_REPLACE:
-		/* replace mode - remove the instrument if it already exists */
-		remove_info(sf, hdr.bank, hdr.instr);
-		break;
-	}
-
-	/* append new layers */
-	for (i = 0; i < hdr.nvoices; i++) {
-		rec = alloc_new_info();
-		if (rec == NULL)
-			return -ENOMEM;
-
-		rec->bank = hdr.bank;
-		rec->instr = hdr.instr;
-		rec->type = V_ST_NORMAL;
-		rec->disabled = FALSE;
-
-		/* copy awe_voice_info parameters */
-		if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) {
-			kfree(rec);
-			return -EFAULT;
-		}
-		offset += AWE_VOICE_INFO_SIZE;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-		if (sf && sf->shared) {
-			if (info_duplicated(sf, rec)) {
-				kfree(rec);
-				continue;
-			}
-		}
-#endif /* allow sharing */
-		if (rec->v.mode & AWE_MODE_INIT_PARM)
-			awe_init_voice_parm(&rec->v.parm);
-		add_sf_info(sf, rec);
-		awe_set_sample(rec);
-		add_info_list(rec);
-	}
-
-	return 0;
-}
-
-
-/* remove instrument layers */
-static int
-awe_remove_info(awe_patch_info *patch, const char __user *addr, int count)
-{
-	unsigned char bank, instr;
-	sf_list *sf;
-
-	if (! patch_opened || (sf = sftail) == NULL) {
-		printk(KERN_WARNING "AWE32: remove_info: patch not opened\n");
-		return -EINVAL;
-	}
-
-	bank = ((unsigned short)patch->optarg >> 8) & 0xff;
-	instr = (unsigned short)patch->optarg & 0xff;
-	if (! remove_info(sf, bank, instr))
-		return -EINVAL;
-	return 0;
-}
-
-
-/* load wave sample data */
-static int
-awe_load_data(awe_patch_info *patch, const char __user *addr, int count)
-{
-	int offset, size;
-	int rc;
-	awe_sample_info tmprec;
-	awe_sample_list *rec;
-	sf_list *sf;
-
-	if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
-		return -ENOMEM;
-
-	size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
-	offset = AWE_PATCH_INFO_SIZE;
-	if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE))
-		return -EFAULT;
-	offset += AWE_SAMPLE_INFO_SIZE;
-	if (size != tmprec.size) {
-		printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n",
-		       tmprec.size, size);
-		return -EINVAL;
-	}
-
-	if (search_sample_index(sf, tmprec.sample) != NULL) {
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-		/* if shared sample, skip this data */
-		if (sf->type & AWE_PAT_SHARED)
-			return 0;
-#endif /* allow sharing */
-		DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
-		return -EINVAL;
-	}
-
-	if ((rec = alloc_new_sample()) == NULL)
-		return -ENOMEM;
-
-	memcpy(&rec->v, &tmprec, sizeof(tmprec));
-
-	if (rec->v.size > 0) {
-		if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) {
-			kfree(rec);
-			return rc;
-		}
-		sf->mem_ptr += rc;
-	}
-
-	add_sf_sample(sf, rec);
-	return 0;
-}
-
-
-/* replace wave sample data */
-static int
-awe_replace_data(awe_patch_info *patch, const char __user *addr, int count)
-{
-	int offset;
-	int size;
-	int rc;
-	int channels;
-	awe_sample_info cursmp;
-	int save_mem_ptr;
-	sf_list *sf;
-	awe_sample_list *rec;
-
-	if (! patch_opened || (sf = sftail) == NULL) {
-		printk(KERN_WARNING "AWE32: replace: patch not opened\n");
-		return -EINVAL;
-	}
-
-	size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
-	offset = AWE_PATCH_INFO_SIZE;
-	if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE))
-		return -EFAULT;
-	offset += AWE_SAMPLE_INFO_SIZE;
-	if (cursmp.size == 0 || size != cursmp.size) {
-		printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n",
-		       cursmp.size, size);
-		return -EINVAL;
-	}
-	channels = patch->optarg;
-	if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
-		printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels);
-		return -EINVAL;
-	}
-
-	for (rec = sf->samples; rec; rec = rec->next) {
-		if (rec->v.sample == cursmp.sample)
-			break;
-	}
-	if (rec == NULL) {
-		printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n",
-		       cursmp.sample);
-		return -EINVAL;
-	}
-		
-	if (rec->v.size != cursmp.size) {
-		printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n",
-		       rec->v.size, cursmp.size);
-		return -EINVAL;
-	}
-
-	save_mem_ptr = awe_free_mem_ptr();
-	sftail->mem_ptr = rec->v.start - awe_mem_start;
-	memcpy(&rec->v, &cursmp, sizeof(cursmp));
-	rec->v.sf_id = current_sf_id;
-	if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0)
-		return rc;
-	sftail->mem_ptr = save_mem_ptr;
-
-	return 0;
-}
-
-
-/*----------------------------------------------------------------*/
-
-static const char __user *readbuf_addr;
-static int readbuf_offs;
-static int readbuf_flags;
-
-/* initialize read buffer */
-static int
-readbuf_init(const char __user *addr, int offset, awe_sample_info *sp)
-{
-	readbuf_addr = addr;
-	readbuf_offs = offset;
-	readbuf_flags = sp->mode_flags;
-	return 0;
-}
-
-/* read directly from user buffer */
-static unsigned short
-readbuf_word(int pos)
-{
-	unsigned short c;
-	/* read from user buffer */
-	if (readbuf_flags & AWE_SAMPLE_8BITS) {
-		unsigned char cc;
-		get_user(cc, (unsigned char __user *)(readbuf_addr + readbuf_offs + pos));
-		c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */
-	} else {
-		get_user(c, (unsigned short __user *)(readbuf_addr + readbuf_offs + pos * 2));
-	}
-	if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
-		c ^= 0x8000; /* unsigned -> signed */
-	return c;
-}
-
-#define readbuf_word_cache	readbuf_word
-#define readbuf_end()		/**/
-
-/*----------------------------------------------------------------*/
-
-#define BLANK_LOOP_START	8
-#define BLANK_LOOP_END		40
-#define BLANK_LOOP_SIZE		48
-
-/* loading onto memory - return the actual written size */
-static int 
-awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *list, int channels)
-{
-	int i, truesize, dram_offset;
-	awe_sample_info *sp = &list->v;
-	int rc;
-
-	/* be sure loop points start < end */
-	if (sp->loopstart > sp->loopend) {
-		int tmp = sp->loopstart;
-		sp->loopstart = sp->loopend;
-		sp->loopend = tmp;
-	}
-
-	/* compute true data size to be loaded */
-	truesize = sp->size;
-	if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))
-		truesize += sp->loopend - sp->loopstart;
-	if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
-		truesize += BLANK_LOOP_SIZE;
-	if (awe_free_mem_ptr() + truesize >= memsize/2) {
-		DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
-		return -ENOSPC;
-	}
-
-	/* recalculate address offset */
-	sp->end -= sp->start;
-	sp->loopstart -= sp->start;
-	sp->loopend -= sp->start;
-
-	dram_offset = awe_free_mem_ptr() + awe_mem_start;
-	sp->start = dram_offset;
-	sp->end += dram_offset;
-	sp->loopstart += dram_offset;
-	sp->loopend += dram_offset;
-
-	/* set the total size (store onto obsolete checksum value) */
-	if (sp->size == 0)
-		sp->checksum = 0;
-	else
-		sp->checksum = truesize;
-
-	if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0)
-		return rc;
-
-	if (readbuf_init(addr, offset, sp) < 0)
-		return -ENOSPC;
-
-	for (i = 0; i < sp->size; i++) {
-		unsigned short c;
-		c = readbuf_word(i);
-		awe_write_dram(c);
-		if (i == sp->loopend &&
-		    (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) {
-			int looplen = sp->loopend - sp->loopstart;
-			/* copy reverse loop */
-			int k;
-			for (k = 1; k <= looplen; k++) {
-				c = readbuf_word_cache(i - k);
-				awe_write_dram(c);
-			}
-			if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) {
-				sp->end += looplen;
-			} else {
-				sp->start += looplen;
-				sp->end += looplen;
-			}
-		}
-	}
-	readbuf_end();
-
-	/* if no blank loop is attached in the sample, add it */
-	if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) {
-		for (i = 0; i < BLANK_LOOP_SIZE; i++)
-			awe_write_dram(0);
-		if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) {
-			sp->loopstart = sp->end + BLANK_LOOP_START;
-			sp->loopend = sp->end + BLANK_LOOP_END;
-		}
-	}
-
-	awe_close_dram();
-
-	/* initialize FM */
-	awe_init_fm();
-
-	return truesize;
-}
-
-
-/*----------------------------------------------------------------*/
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* calculate GUS envelope time:
- * is this correct?  i have no idea..
- */
-static int
-calc_gus_envelope_time(int rate, int start, int end)
-{
-	int r, p, t;
-	r = (3 - ((rate >> 6) & 3)) * 3;
-	p = rate & 0x3f;
-	t = end - start;
-	if (t < 0) t = -t;
-	if (13 > r)
-		t = t << (13 - r);
-	else
-		t = t >> (r - 13);
-	return (t * 10) / (p * 441);
-}
-
-#define calc_gus_sustain(val)  (0x7f - vol_table[(val)/2])
-#define calc_gus_attenuation(val)	vol_table[(val)/2]
-
-/* load GUS patch */
-static int
-awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag)
-{
-	struct patch_info patch;
-	awe_voice_info *rec;
-	awe_sample_info *smp;
-	awe_voice_list *vrec;
-	awe_sample_list *smprec;
-	int sizeof_patch;
-	int note, rc;
-	sf_list *sf;
-
-	sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
-	if (size < sizeof_patch) {
-		printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
-		return -EINVAL;
-	}
-	if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs))
-		return -EFAULT;
-	size -= sizeof_patch;
-	if (size < patch.len) {
-		printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n",
-		       size, patch.len);
-		return -EINVAL;
-	}
-	if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL)
-		return -ENOMEM;
-	if ((smprec = alloc_new_sample()) == NULL)
-		return -ENOMEM;
-	if ((vrec = alloc_new_info()) == NULL) {
-		kfree(smprec);
-		return -ENOMEM;
-	}
-
-	smp = &smprec->v;
-	smp->sample = sf->num_sample;
-	smp->start = 0;
-	smp->end = patch.len;
-	smp->loopstart = patch.loop_start;
-	smp->loopend = patch.loop_end;
-	smp->size = patch.len;
-
-	/* set up mode flags */
-	smp->mode_flags = 0;
-	if (!(patch.mode & WAVE_16_BITS))
-		smp->mode_flags |= AWE_SAMPLE_8BITS;
-	if (patch.mode & WAVE_UNSIGNED)
-		smp->mode_flags |= AWE_SAMPLE_UNSIGNED;
-	smp->mode_flags |= AWE_SAMPLE_NO_BLANK;
-	if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))
-		smp->mode_flags |= AWE_SAMPLE_SINGLESHOT;
-	if (patch.mode & WAVE_BIDIR_LOOP)
-		smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP;
-	if (patch.mode & WAVE_LOOP_BACK)
-		smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP;
-
-	DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags));
-	if (patch.mode & WAVE_16_BITS) {
-		/* convert to word offsets */
-		smp->size /= 2;
-		smp->end /= 2;
-		smp->loopstart /= 2;
-		smp->loopend /= 2;
-	}
-	smp->checksum_flag = 0;
-	smp->checksum = 0;
-
-	if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) {
-		kfree(vrec);
-		return rc;
-	}
-	sf->mem_ptr += rc;
-	add_sf_sample(sf, smprec);
-
-	/* set up voice info */
-	rec = &vrec->v;
-	awe_init_voice_info(rec);
-	rec->sample = sf->num_info; /* the last sample */
-	rec->rate_offset = calc_rate_offset(patch.base_freq);
-	note = freq_to_note(patch.base_note);
-	rec->root = note / 100;
-	rec->tune = -(note % 100);
-	rec->low = freq_to_note(patch.low_note) / 100;
-	rec->high = freq_to_note(patch.high_note) / 100;
-	DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n",
-		       rec->rate_offset, note,
-		       rec->low, rec->high,
-	      patch.low_note, patch.high_note));
-	/* panning position; -128 - 127 => 0-127 */
-	rec->pan = (patch.panning + 128) / 2;
-
-	/* detuning is ignored */
-	/* 6points volume envelope */
-	if (patch.mode & WAVE_ENVELOPES) {
-		int attack, hold, decay, release;
-		attack = calc_gus_envelope_time
-			(patch.env_rate[0], 0, patch.env_offset[0]);
-		hold = calc_gus_envelope_time
-			(patch.env_rate[1], patch.env_offset[0],
-			 patch.env_offset[1]);
-		decay = calc_gus_envelope_time
-			(patch.env_rate[2], patch.env_offset[1],
-			 patch.env_offset[2]);
-		release = calc_gus_envelope_time
-			(patch.env_rate[3], patch.env_offset[1],
-			 patch.env_offset[4]);
-		release += calc_gus_envelope_time
-			(patch.env_rate[4], patch.env_offset[3],
-			 patch.env_offset[4]);
-		release += calc_gus_envelope_time
-			(patch.env_rate[5], patch.env_offset[4],
-			 patch.env_offset[5]);
-		rec->parm.volatkhld = (calc_parm_hold(hold) << 8) |
-			calc_parm_attack(attack);
-		rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
-			calc_parm_decay(decay);
-		rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
-		DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release));
-		rec->attenuation = calc_gus_attenuation(patch.env_offset[0]);
-	}
-
-	/* tremolo effect */
-	if (patch.mode & WAVE_TREMOLO) {
-		int rate = (patch.tremolo_rate * 1000 / 38) / 42;
-		rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
-		DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n",
-			       patch.tremolo_rate, patch.tremolo_depth,
-			       rec->parm.tremfrq));
-	}
-	/* vibrato effect */
-	if (patch.mode & WAVE_VIBRATO) {
-		int rate = (patch.vibrato_rate * 1000 / 38) / 42;
-		rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
-		DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n",
-			       patch.tremolo_rate, patch.tremolo_depth,
-			       rec->parm.tremfrq));
-	}
-	
-	/* scale_freq, scale_factor, volume, and fractions not implemented */
-
-	/* append to the tail of the list */
-	vrec->bank = ctrls[AWE_MD_GUS_BANK];
-	vrec->instr = patch.instr_no;
-	vrec->disabled = FALSE;
-	vrec->type = V_ST_NORMAL;
-
-	add_sf_info(sf, vrec);
-	add_info_list(vrec);
-
-	/* set the voice index */
-	awe_set_sample(vrec);
-
-	return 0;
-}
-
-#endif  /* AWE_HAS_GUS_COMPATIBILITY */
-
-/*
- * sample and voice list handlers
- */
-
-/* append this to the current sf list */
-static void add_sf_info(sf_list *sf, awe_voice_list *rec)
-{
-	if (sf == NULL)
-		return;
-	rec->holder = sf;
-	rec->v.sf_id = sf->sf_id;
-	if (sf->last_infos)
-		sf->last_infos->next = rec;
-	else
-		sf->infos = rec;
-	sf->last_infos = rec;
-	rec->next = NULL;
-	sf->num_info++;
-}
-
-/* prepend this sample to sf list */
-static void add_sf_sample(sf_list *sf, awe_sample_list *rec)
-{
-	if (sf == NULL)
-		return;
-	rec->holder = sf;
-	rec->v.sf_id = sf->sf_id;
-	if (sf->last_samples)
-		sf->last_samples->next = rec;
-	else
-		sf->samples = rec;
-	sf->last_samples = rec;
-	rec->next = NULL;
-	sf->num_sample++;
-}
-
-/* purge the old records which don't belong with the same file id */
-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next)
-{
-	rec->next_instr = next;
-	if (rec->bank == AWE_DRUM_BANK) {
-		/* remove samples with the same note range */
-		awe_voice_list *cur, *prev = rec;
-		int low = rec->v.low;
-		int high = rec->v.high;
-		for (cur = next; cur; cur = cur->next_instr) {
-			if (cur->v.low == low &&
-			    cur->v.high == high &&
-			    ! is_identical_holder(cur->holder, rec->holder))
-				prev->next_instr = cur->next_instr;
-			else
-				prev = cur;
-		}
-	} else {
-		if (! is_identical_holder(next->holder, rec->holder))
-			/* remove all samples */
-			rec->next_instr = NULL;
-	}
-}
-
-/* prepend to top of the preset table */
-static void add_info_list(awe_voice_list *rec)
-{
-	awe_voice_list *prev, *cur;
-	int key;
-
-	if (rec->disabled)
-		return;
-
-	key = awe_search_key(rec->bank, rec->instr, rec->v.low);
-	prev = NULL;
-	for (cur = preset_table[key]; cur; cur = cur->next_bank) {
-		/* search the first record with the same bank number */
-		if (cur->instr == rec->instr && cur->bank == rec->bank) {
-			/* replace the list with the new record */
-			rec->next_bank = cur->next_bank;
-			if (prev)
-				prev->next_bank = rec;
-			else
-				preset_table[key] = rec;
-			purge_old_list(rec, cur);
-			return;
-		}
-		prev = cur;
-	}
-
-	/* this is the first bank record.. just add this */
-	rec->next_instr = NULL;
-	rec->next_bank = preset_table[key];
-	preset_table[key] = rec;
-}
-
-/* remove samples later than the specified sf_id */
-static void
-awe_remove_samples(int sf_id)
-{
-	sf_list *p, *prev;
-
-	if (sf_id <= 0) {
-		awe_reset_samples();
-		return;
-	}
-	/* already removed? */
-	if (current_sf_id <= sf_id)
-		return;
-
-	for (p = sftail; p; p = prev) {
-		if (p->sf_id <= sf_id)
-			break;
-		prev = p->prev;
-		awe_free_sf(p);
-	}
-	sftail = p;
-	if (sftail) {
-		sf_id = sftail->sf_id;
-		sftail->next = NULL;
-	} else {
-		sf_id = 0;
-		sfhead = NULL;
-	}
-	current_sf_id = sf_id;
-	if (locked_sf_id > sf_id)
-		locked_sf_id = sf_id;
-
-	rebuild_preset_list();
-}
-
-/* rebuild preset search list */
-static void rebuild_preset_list(void)
-{
-	sf_list *p;
-	awe_voice_list *rec;
-
-	memset(preset_table, 0, sizeof(preset_table));
-
-	for (p = sfhead; p; p = p->next) {
-		for (rec = p->infos; rec; rec = rec->next)
-			add_info_list(rec);
-	}
-}
-
-/* compare the given sf_id pair */
-static int is_identical_holder(sf_list *sf1, sf_list *sf2)
-{
-	if (sf1 == NULL || sf2 == NULL)
-		return FALSE;
-	if (sf1 == sf2)
-		return TRUE;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-	{
-		/* compare with the sharing id */
-		sf_list *p;
-		int counter = 0;
-		if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */
-			sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp;
-		}
-		for (p = sf1->shared; p; p = p->shared) {
-			if (counter++ > current_sf_id)
-				break; /* strange sharing loop.. quit */
-			if (p == sf2)
-				return TRUE;
-		}
-	}
-#endif /* allow sharing */
-	return FALSE;
-}
-
-/* search the sample index matching with the given sample id */
-static awe_sample_list *
-search_sample_index(sf_list *sf, int sample)
-{
-	awe_sample_list *p;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-	int counter = 0;
-	while (sf) {
-		for (p = sf->samples; p; p = p->next) {
-			if (p->v.sample == sample)
-				return p;
-		}
-		sf = sf->shared;
-		if (counter++ > current_sf_id)
-			break; /* strange sharing loop.. quit */
-	}
-#else
-	if (sf) {
-		for (p = sf->samples; p; p = p->next) {
-			if (p->v.sample == sample)
-				return p;
-		}
-	}
-#endif
-	return NULL;
-}
-
-/* search the specified sample */
-/* non-zero = found */
-static short
-awe_set_sample(awe_voice_list *rec)
-{
-	awe_sample_list *smp;
-	awe_voice_info *vp = &rec->v;
-
-	vp->index = 0;
-	if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL)
-		return 0;
-
-	/* set the actual sample offsets */
-	vp->start += smp->v.start;
-	vp->end += smp->v.end;
-	vp->loopstart += smp->v.loopstart;
-	vp->loopend += smp->v.loopend;
-	/* copy mode flags */
-	vp->mode = smp->v.mode_flags;
-	/* set flag */
-	vp->index = 1;
-
-	return 1;
-}
-
-
-/*
- * voice allocation
- */
-
-/* look for all voices associated with the specified note & velocity */
-static int
-awe_search_multi_voices(awe_voice_list *rec, int note, int velocity,
-			awe_voice_info **vlist)
-{
-	int nvoices;
-
-	nvoices = 0;
-	for (; rec; rec = rec->next_instr) {
-		if (note >= rec->v.low &&
-		    note <= rec->v.high &&
-		    velocity >= rec->v.vellow &&
-		    velocity <= rec->v.velhigh) {
-			if (rec->type == V_ST_MAPPED) {
-				/* mapper */
-				vlist[0] = &rec->v;
-				return -1;
-			}
-			vlist[nvoices++] = &rec->v;
-			if (nvoices >= AWE_MAX_VOICES)
-				break;
-		}
-	}
-	return nvoices;	
-}
-
-/* store the voice list from the specified note and velocity.
-   if the preset is mapped, seek for the destination preset, and rewrite
-   the note number if necessary.
-   */
-static int
-really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist)
-{
-	int nvoices;
-	awe_voice_list *vrec;
-	int level = 0;
-
-	for (;;) {
-		vrec = awe_search_instr(bank, instr, *note);
-		nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
-		if (nvoices == 0) {
-			if (bank == AWE_DRUM_BANK)
-				/* search default drumset */
-				vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note);
-			else
-				/* search default preset */
-				vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note);
-			nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
-		}
-		if (nvoices == 0) {
-			if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0)
-				/* search default drumset */
-				vrec = awe_search_instr(bank, 0, *note);
-			else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0)
-				/* search default preset */
-				vrec = awe_search_instr(0, instr, *note);
-			nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
-		}
-		if (nvoices < 0) { /* mapping */
-			int key = vlist[0]->fixkey;
-			instr = vlist[0]->start;
-			bank = vlist[0]->end;
-			if (level++ > 5) {
-				printk(KERN_ERR "AWE32: too deep mapping level\n");
-				return 0;
-			}
-			if (key >= 0)
-				*note = key;
-		} else
-			break;
-	}
-
-	return nvoices;
-}
-
-/* allocate voices corresponding note and velocity; supports multiple insts. */
-static void
-awe_alloc_multi_voices(int ch, int note, int velocity, int key)
-{
-	int i, v, nvoices, bank;
-	awe_voice_info *vlist[AWE_MAX_VOICES];
-
-	if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch))
-		bank = AWE_DRUM_BANK; /* always search drumset */
-	else
-		bank = channels[ch].bank;
-
-	/* check the possible voices; note may be changeable if mapped */
-	nvoices = really_alloc_voices(bank, channels[ch].instr,
-				      &note, velocity, vlist);
-
-	/* set the voices */
-	current_alloc_time++;
-	for (i = 0; i < nvoices; i++) {
-		v = awe_clear_voice();
-		voices[v].key = key;
-		voices[v].ch = ch;
-		voices[v].note = note;
-		voices[v].velocity = velocity;
-		voices[v].time = current_alloc_time;
-		voices[v].cinfo = &channels[ch];
-		voices[v].sample = vlist[i];
-		voices[v].state = AWE_ST_MARK;
-		voices[v].layer = nvoices - i - 1;  /* in reverse order */
-	}
-
-	/* clear the mark in allocated voices */
-	for (i = 0; i < awe_max_voices; i++) {
-		if (voices[i].state == AWE_ST_MARK)
-			voices[i].state = AWE_ST_OFF;
-			
-	}
-}
-
-
-/* search an empty voice.
-   if no empty voice is found, at least terminate a voice
-   */
-static int
-awe_clear_voice(void)
-{
-	enum {
-		OFF=0, RELEASED, SUSTAINED, PLAYING, END
-	};
-	struct voice_candidate_t {
-		int best;
-		int time;
-		int vtarget;
-	} candidate[END];
-	int i, type, vtarget;
-
-	vtarget = 0xffff;
-	for (type = OFF; type < END; type++) {
-		candidate[type].best = -1;
-		candidate[type].time = current_alloc_time + 1;
-		candidate[type].vtarget = vtarget;
-	}
-
-	for (i = 0; i < awe_max_voices; i++) {
-		if (voices[i].state & AWE_ST_OFF)
-			type = OFF;
-		else if (voices[i].state & AWE_ST_RELEASED)
-			type = RELEASED;
-		else if (voices[i].state & AWE_ST_SUSTAINED)
-			type = SUSTAINED;
-		else if (voices[i].state & ~AWE_ST_MARK)
-			type = PLAYING;
-		else
-			continue;
-#ifdef AWE_CHECK_VTARGET
-		/* get current volume */
-		vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
-#endif
-		if (candidate[type].best < 0 ||
-		    vtarget < candidate[type].vtarget ||
-		    (vtarget == candidate[type].vtarget &&
-		     voices[i].time < candidate[type].time)) {
-			candidate[type].best = i;
-			candidate[type].time = voices[i].time;
-			candidate[type].vtarget = vtarget;
-		}
-	}
-
-	for (type = OFF; type < END; type++) {
-		if ((i = candidate[type].best) >= 0) {
-			if (voices[i].state != AWE_ST_OFF)
-				awe_terminate(i);
-			awe_voice_init(i, TRUE);
-			return i;
-		}
-	}
-	return 0;
-}
-
-
-/* search sample for the specified note & velocity and set it on the voice;
- * note that voice is the voice index (not channel index)
- */
-static void
-awe_alloc_one_voice(int voice, int note, int velocity)
-{
-	int ch, nvoices, bank;
-	awe_voice_info *vlist[AWE_MAX_VOICES];
-
-	ch = voices[voice].ch;
-	if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
-		bank = AWE_DRUM_BANK; /* always search drumset */
-	else
-		bank = voices[voice].cinfo->bank;
-
-	nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr,
-				      &note, velocity, vlist);
-	if (nvoices > 0) {
-		voices[voice].time = ++current_alloc_time;
-		voices[voice].sample = vlist[0]; /* use the first one */
-		voices[voice].layer = 0;
-		voices[voice].note = note;
-		voices[voice].velocity = velocity;
-	}
-}
-
-
-/*
- * sequencer2 functions
- */
-
-/* search an empty voice; used by sequencer2 */
-static int
-awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
-	playing_mode = AWE_PLAY_MULTI2;
-	awe_info.nr_voices = AWE_MAX_CHANNELS;
-	return awe_clear_voice();
-}
-
-
-/* set up voice; used by sequencer2 */
-static void
-awe_setup_voice(int dev, int voice, int chn)
-{
-	struct channel_info *info;
-	if (synth_devs[dev] == NULL ||
-	    (info = &synth_devs[dev]->chn_info[chn]) == NULL)
-		return;
-
-	if (voice < 0 || voice >= awe_max_voices)
-		return;
-
-	DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn));
-	channels[chn].expression_vol = info->controllers[CTL_EXPRESSION];
-	channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME];
-	channels[chn].panning =
-		info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */
-	channels[chn].bender = info->bender_value; /* zero center */
-	channels[chn].bank = info->controllers[CTL_BANK_SELECT];
-	channels[chn].sustained = info->controllers[CTL_SUSTAIN];
-	if (info->controllers[CTL_EXT_EFF_DEPTH]) {
-		FX_SET(&channels[chn].fx, AWE_FX_REVERB,
-		       info->controllers[CTL_EXT_EFF_DEPTH] * 2);
-	}
-	if (info->controllers[CTL_CHORUS_DEPTH]) {
-		FX_SET(&channels[chn].fx, AWE_FX_CHORUS,
-		       info->controllers[CTL_CHORUS_DEPTH] * 2);
-	}
-	awe_set_instr(dev, chn, info->pgm_num);
-}
-
-
-#ifdef CONFIG_AWE32_MIXER
-/*
- * AWE32 mixer device control
- */
-
-static int awe_mixer_ioctl(int dev, unsigned int cmd, void __user *arg);
-
-static int my_mixerdev = -1;
-
-static struct mixer_operations awe_mixer_operations = {
-	.owner	= THIS_MODULE,
-	.id	= "AWE",
-	.name	= "AWE32 Equalizer",
-	.ioctl	= awe_mixer_ioctl,
-};
-
-static void __init attach_mixer(void)
-{
-	if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
-		mixer_devs[my_mixerdev] = &awe_mixer_operations;
-	}
-}
-
-static void unload_mixer(void)
-{
-	if (my_mixerdev >= 0)
-		sound_unload_mixerdev(my_mixerdev);
-}
-
-static int
-awe_mixer_ioctl(int dev, unsigned int cmd, void __user * arg)
-{
-	int i, level, value;
-
-	if (((cmd >> 8) & 0xff) != 'M')
-		return -EINVAL;
-
-	if (get_user(level, (int __user *)arg))
-		return -EFAULT;
-	level = ((level & 0xff) + (level >> 8)) / 2;
-	DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
-
-	if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
-		switch (cmd & 0xff) {
-		case SOUND_MIXER_BASS:
-			value = level * 12 / 100;
-			if (value >= 12)
-				value = 11;
-			ctrls[AWE_MD_BASS_LEVEL] = value;
-			awe_update_equalizer();
-			break;
-		case SOUND_MIXER_TREBLE:
-			value = level * 12 / 100;
-			if (value >= 12)
-				value = 11;
-			ctrls[AWE_MD_TREBLE_LEVEL] = value;
-			awe_update_equalizer();
-			break;
-		case SOUND_MIXER_VOLUME:
-			level = level * 127 / 100;
-			if (level >= 128) level = 127;
-			atten_relative = FALSE;
-			atten_offset = vol_table[level];
-			awe_update_volume();
-			break;
-		}
-	}
-	switch (cmd & 0xff) {
-	case SOUND_MIXER_BASS:
-		level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24;
-		level = (level << 8) | level;
-		break;
-	case SOUND_MIXER_TREBLE:
-		level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24;
-		level = (level << 8) | level;
-		break;
-	case SOUND_MIXER_VOLUME:
-		value = atten_offset;
-		if (atten_relative)
-			value += ctrls[AWE_MD_ZERO_ATTEN];
-		for (i = 127; i > 0; i--) {
-			if (value <= vol_table[i])
-				break;
-		}
-		level = i * 100 / 127;
-		level = (level << 8) | level;
-		break;
-	case SOUND_MIXER_DEVMASK:
-		level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME;
-		break;
-	default:
-		level = 0;
-		break;
-	}
-	if (put_user(level, (int __user *)arg))
-		return -EFAULT;
-	return level;
-}
-#endif /* CONFIG_AWE32_MIXER */
-
-
-/*
- * initialization of Emu8000
- */
-
-/* intiailize audio channels */
-static void
-awe_init_audio(void)
-{
-	int ch;
-
-	/* turn off envelope engines */
-	for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
-		awe_poke(AWE_DCYSUSV(ch), 0x80);
-	}
-  
-	/* reset all other parameters to zero */
-	for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
-		awe_poke(AWE_ENVVOL(ch), 0);
-		awe_poke(AWE_ENVVAL(ch), 0);
-		awe_poke(AWE_DCYSUS(ch), 0);
-		awe_poke(AWE_ATKHLDV(ch), 0);
-		awe_poke(AWE_LFO1VAL(ch), 0);
-		awe_poke(AWE_ATKHLD(ch), 0);
-		awe_poke(AWE_LFO2VAL(ch), 0);
-		awe_poke(AWE_IP(ch), 0);
-		awe_poke(AWE_IFATN(ch), 0);
-		awe_poke(AWE_PEFE(ch), 0);
-		awe_poke(AWE_FMMOD(ch), 0);
-		awe_poke(AWE_TREMFRQ(ch), 0);
-		awe_poke(AWE_FM2FRQ2(ch), 0);
-		awe_poke_dw(AWE_PTRX(ch), 0);
-		awe_poke_dw(AWE_VTFT(ch), 0);
-		awe_poke_dw(AWE_PSST(ch), 0);
-		awe_poke_dw(AWE_CSL(ch), 0);
-		awe_poke_dw(AWE_CCCA(ch), 0);
-	}
-
-	for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
-		awe_poke_dw(AWE_CPF(ch), 0);
-		awe_poke_dw(AWE_CVCF(ch), 0);
-	}
-}
-
-
-/* initialize DMA address */
-static void
-awe_init_dma(void)
-{
-	awe_poke_dw(AWE_SMALR, 0);
-	awe_poke_dw(AWE_SMARR, 0);
-	awe_poke_dw(AWE_SMALW, 0);
-	awe_poke_dw(AWE_SMARW, 0);
-}
-
-
-/* initialization arrays; from ADIP */
-
-static unsigned short init1[128] = {
-	0x03ff, 0x0030,  0x07ff, 0x0130, 0x0bff, 0x0230,  0x0fff, 0x0330,
-	0x13ff, 0x0430,  0x17ff, 0x0530, 0x1bff, 0x0630,  0x1fff, 0x0730,
-	0x23ff, 0x0830,  0x27ff, 0x0930, 0x2bff, 0x0a30,  0x2fff, 0x0b30,
-	0x33ff, 0x0c30,  0x37ff, 0x0d30, 0x3bff, 0x0e30,  0x3fff, 0x0f30,
-
-	0x43ff, 0x0030,  0x47ff, 0x0130, 0x4bff, 0x0230,  0x4fff, 0x0330,
-	0x53ff, 0x0430,  0x57ff, 0x0530, 0x5bff, 0x0630,  0x5fff, 0x0730,
-	0x63ff, 0x0830,  0x67ff, 0x0930, 0x6bff, 0x0a30,  0x6fff, 0x0b30,
-	0x73ff, 0x0c30,  0x77ff, 0x0d30, 0x7bff, 0x0e30,  0x7fff, 0x0f30,
-
-	0x83ff, 0x0030,  0x87ff, 0x0130, 0x8bff, 0x0230,  0x8fff, 0x0330,
-	0x93ff, 0x0430,  0x97ff, 0x0530, 0x9bff, 0x0630,  0x9fff, 0x0730,
-	0xa3ff, 0x0830,  0xa7ff, 0x0930, 0xabff, 0x0a30,  0xafff, 0x0b30,
-	0xb3ff, 0x0c30,  0xb7ff, 0x0d30, 0xbbff, 0x0e30,  0xbfff, 0x0f30,
-
-	0xc3ff, 0x0030,  0xc7ff, 0x0130, 0xcbff, 0x0230,  0xcfff, 0x0330,
-	0xd3ff, 0x0430,  0xd7ff, 0x0530, 0xdbff, 0x0630,  0xdfff, 0x0730,
-	0xe3ff, 0x0830,  0xe7ff, 0x0930, 0xebff, 0x0a30,  0xefff, 0x0b30,
-	0xf3ff, 0x0c30,  0xf7ff, 0x0d30, 0xfbff, 0x0e30,  0xffff, 0x0f30,
-};
-
-static unsigned short init2[128] = {
-	0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
-	0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
-	0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
-	0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
-
-	0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
-	0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
-	0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
-	0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
-
-	0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
-	0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
-	0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
-	0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
-
-	0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
-	0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
-	0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
-	0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
-};
-
-static unsigned short init3[128] = {
-	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
-	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
-	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
-	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
-
-	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
-	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
-	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
-	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
-
-	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
-	0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
-	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
-	0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
-
-	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
-	0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
-	0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
-	0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-static unsigned short init4[128] = {
-	0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
-	0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
-	0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
-	0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
-
-	0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
-	0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
-	0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
-	0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
-
-	0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
-	0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
-	0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
-	0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
-
-	0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
-	0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
-	0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
-	0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-
-/* send initialization arrays to start up */
-static void
-awe_init_array(void)
-{
-	awe_send_array(init1);
-	awe_wait(1024);
-	awe_send_array(init2);
-	awe_send_array(init3);
-	awe_poke_dw(AWE_HWCF4, 0);
-	awe_poke_dw(AWE_HWCF5, 0x83);
-	awe_poke_dw(AWE_HWCF6, 0x8000);
-	awe_send_array(init4);
-}
-
-/* send an initialization array */
-static void
-awe_send_array(unsigned short *data)
-{
-	int i;
-	unsigned short *p;
-
-	p = data;
-	for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-		awe_poke(AWE_INIT1(i), *p);
-	for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-		awe_poke(AWE_INIT2(i), *p);
-	for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-		awe_poke(AWE_INIT3(i), *p);
-	for (i = 0; i < AWE_MAX_VOICES; i++, p++)
-		awe_poke(AWE_INIT4(i), *p);
-}
-
-
-/*
- * set up awe32 channels to some known state.
- */
-
-/* set the envelope & LFO parameters to the default values; see ADIP */
-static void
-awe_tweak_voice(int i)
-{
-	/* set all mod/vol envelope shape to minimum */
-	awe_poke(AWE_ENVVOL(i), 0x8000);
-	awe_poke(AWE_ENVVAL(i), 0x8000);
-	awe_poke(AWE_DCYSUS(i), 0x7F7F);
-	awe_poke(AWE_ATKHLDV(i), 0x7F7F);
-	awe_poke(AWE_ATKHLD(i), 0x7F7F);
-	awe_poke(AWE_PEFE(i), 0);  /* mod envelope height to zero */
-	awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */
-	awe_poke(AWE_LFO2VAL(i), 0x8000);
-	awe_poke(AWE_IP(i), 0xE000);	/* no pitch shift */
-	awe_poke(AWE_IFATN(i), 0xFF00);	/* volume to minimum */
-	awe_poke(AWE_FMMOD(i), 0);
-	awe_poke(AWE_TREMFRQ(i), 0);
-	awe_poke(AWE_FM2FRQ2(i), 0);
-}
-
-static void
-awe_tweak(void)
-{
-	int i;
-	/* reset all channels */
-	for (i = 0; i < awe_max_voices; i++)
-		awe_tweak_voice(i);
-}
-
-
-/*
- *  initializes the FM section of AWE32;
- *   see Vince Vu's unofficial AWE32 programming guide
- */
-
-static void
-awe_init_fm(void)
-{
-#ifndef AWE_ALWAYS_INIT_FM
-	/* if no extended memory is on board.. */
-	if (memsize <= 0)
-		return;
-#endif
-	DEBUG(3,printk("AWE32: initializing FM\n"));
-
-	/* Initialize the last two channels for DRAM refresh and producing
-	   the reverb and chorus effects for Yamaha OPL-3 synthesizer */
-
-	/* 31: FM left channel, 0xffffe0-0xffffe8 */
-	awe_poke(AWE_DCYSUSV(30), 0x80);
-	awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */
-	awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 |
-		    (DEF_FM_CHORUS_DEPTH << 24));
-	awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8));
-	awe_poke_dw(AWE_CPF(30), 0);
-	awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3);
-
-	/* 32: FM right channel, 0xfffff0-0xfffff8 */
-	awe_poke(AWE_DCYSUSV(31), 0x80);
-	awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */
-	awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 |
-		    (DEF_FM_CHORUS_DEPTH << 24));
-	awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8));
-	awe_poke_dw(AWE_CPF(31), 0x8000);
-	awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3);
-
-	/* skew volume & cutoff */
-	awe_poke_dw(AWE_VTFT(30), 0x8000FFFF);
-	awe_poke_dw(AWE_VTFT(31), 0x8000FFFF);
-
-	voices[30].state = AWE_ST_FM;
-	voices[31].state = AWE_ST_FM;
-
-	/* change maximum channels to 30 */
-	awe_max_voices = AWE_NORMAL_VOICES;
-	if (playing_mode == AWE_PLAY_DIRECT)
-		awe_info.nr_voices = awe_max_voices;
-	else
-		awe_info.nr_voices = AWE_MAX_CHANNELS;
-	voice_alloc->max_voice = awe_max_voices;
-}
-
-/*
- *  AWE32 DRAM access routines
- */
-
-/* open DRAM write accessing mode */
-static int
-awe_open_dram_for_write(int offset, int channels)
-{
-	int vidx[AWE_NORMAL_VOICES];
-	int i;
-
-	if (channels < 0 || channels >= AWE_NORMAL_VOICES) {
-		channels = AWE_NORMAL_VOICES;
-		for (i = 0; i < AWE_NORMAL_VOICES; i++)
-			vidx[i] = i;
-	} else {
-		for (i = 0; i < channels; i++) {
-			vidx[i] = awe_clear_voice();
-			voices[vidx[i]].state = AWE_ST_MARK;
-		}
-	}
-
-	/* use all channels for DMA transfer */
-	for (i = 0; i < channels; i++) {
-		if (vidx[i] < 0) continue;
-		awe_poke(AWE_DCYSUSV(vidx[i]), 0x80);
-		awe_poke_dw(AWE_VTFT(vidx[i]), 0);
-		awe_poke_dw(AWE_CVCF(vidx[i]), 0);
-		awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000);
-		awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000);
-		awe_poke_dw(AWE_PSST(vidx[i]), 0);
-		awe_poke_dw(AWE_CSL(vidx[i]), 0);
-		awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000);
-		voices[vidx[i]].state = AWE_ST_DRAM;
-	}
-	/* point channels 31 & 32 to ROM samples for DRAM refresh */
-	awe_poke_dw(AWE_VTFT(30), 0);
-	awe_poke_dw(AWE_PSST(30), 0x1d8);
-	awe_poke_dw(AWE_CSL(30), 0x1e0);
-	awe_poke_dw(AWE_CCCA(30), 0x1d8);
-	awe_poke_dw(AWE_VTFT(31), 0);
-	awe_poke_dw(AWE_PSST(31), 0x1d8);
-	awe_poke_dw(AWE_CSL(31), 0x1e0);
-	awe_poke_dw(AWE_CCCA(31), 0x1d8);
-	voices[30].state = AWE_ST_FM;
-	voices[31].state = AWE_ST_FM;
-
-	/* if full bit is on, not ready to write on */
-	if (awe_peek_dw(AWE_SMALW) & 0x80000000) {
-		for (i = 0; i < channels; i++) {
-			awe_poke_dw(AWE_CCCA(vidx[i]), 0);
-			voices[vidx[i]].state = AWE_ST_OFF;
-		}
-		printk("awe: not ready to write..\n");
-		return -EPERM;
-	}
-
-	/* set address to write */
-	awe_poke_dw(AWE_SMALW, offset);
-
-	return 0;
-}
-
-/* open DRAM for RAM size detection */
-static void
-awe_open_dram_for_check(void)
-{
-	int i;
-	for (i = 0; i < AWE_NORMAL_VOICES; i++) {
-		awe_poke(AWE_DCYSUSV(i), 0x80);
-		awe_poke_dw(AWE_VTFT(i), 0);
-		awe_poke_dw(AWE_CVCF(i), 0);
-		awe_poke_dw(AWE_PTRX(i), 0x40000000);
-		awe_poke_dw(AWE_CPF(i), 0x40000000);
-		awe_poke_dw(AWE_PSST(i), 0);
-		awe_poke_dw(AWE_CSL(i), 0);
-		if (i & 1) /* DMA write */
-			awe_poke_dw(AWE_CCCA(i), 0x06000000);
-		else	   /* DMA read */
-			awe_poke_dw(AWE_CCCA(i), 0x04000000);
-		voices[i].state = AWE_ST_DRAM;
-	}
-}
-
-
-/* close dram access */
-static void
-awe_close_dram(void)
-{
-	int i;
-	/* wait until FULL bit in SMAxW register be false */
-	for (i = 0; i < 10000; i++) {
-		if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
-			break;
-		awe_wait(10);
-	}
-
-	for (i = 0; i < AWE_NORMAL_VOICES; i++) {
-		if (voices[i].state == AWE_ST_DRAM) {
-			awe_poke_dw(AWE_CCCA(i), 0);
-			awe_poke(AWE_DCYSUSV(i), 0x807F);
-			voices[i].state = AWE_ST_OFF;
-		}
-	}
-}
-
-
-/*
- * check dram size on AWE board
- */
-
-/* any three numbers you like */
-#define UNIQUE_ID1	0x1234
-#define UNIQUE_ID2	0x4321
-#define UNIQUE_ID3	0xABCD
-
-static void __init
-awe_check_dram(void)
-{
-	if (awe_present) /* already initialized */
-		return;
-
-	if (memsize >= 0) { /* given by config file or module option */
-		memsize *= 1024; /* convert to Kbytes */
-		return;
-	}
-
-	awe_open_dram_for_check();
-
-	memsize = 0;
-
-	/* set up unique two id numbers */
-	awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
-	awe_poke(AWE_SMLD, UNIQUE_ID1);
-	awe_poke(AWE_SMLD, UNIQUE_ID2);
-
-	while (memsize < AWE_MAX_DRAM_SIZE) {
-		awe_wait(5);
-		/* read a data on the DRAM start address */
-		awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
-		awe_peek(AWE_SMLD); /* discard stale data  */
-		if (awe_peek(AWE_SMLD) != UNIQUE_ID1)
-			break;
-		if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
-			break;
-		memsize += 512;  /* increment 512kbytes */
-		/* Write a unique data on the test address;
-		 * if the address is out of range, the data is written on
-		 * 0x200000(=AWE_DRAM_OFFSET).  Then the two id words are
-		 * broken by this data.
-		 */
-		awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L);
-		awe_poke(AWE_SMLD, UNIQUE_ID3);
-		awe_wait(5);
-		/* read a data on the just written DRAM address */
-		awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L);
-		awe_peek(AWE_SMLD); /* discard stale data  */
-		if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
-			break;
-	}
-	awe_close_dram();
-
-	DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize));
-
-	/* convert to Kbytes */
-	memsize *= 1024;
-}
-
-
-/*----------------------------------------------------------------*/
-
-/*
- * chorus and reverb controls; from VV's guide
- */
-
-/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
-static char chorus_defined[AWE_CHORUS_NUMBERS];
-static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = {
-	{0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
-	{0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
-	{0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
-	{0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
-	{0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
-	{0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
-	{0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */
-	{0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */
-};
-
-static int
-awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count)
-{
-	if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
-		printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg);
-		return -EINVAL;
-	}
-	if (count < sizeof(awe_chorus_fx_rec)) {
-		printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n");
-		return -EINVAL;
-	}
-	if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
-			   sizeof(awe_chorus_fx_rec)))
-		return -EFAULT;
-	chorus_defined[patch->optarg] = TRUE;
-	return 0;
-}
-
-static void
-awe_set_chorus_mode(int effect)
-{
-	if (effect < 0 || effect >= AWE_CHORUS_NUMBERS ||
-	    (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect]))
-		return;
-	awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback);
-	awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset);
-	awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth);
-	awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay);
-	awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq);
-	awe_poke_dw(AWE_HWCF6, 0x8000);
-	awe_poke_dw(AWE_HWCF7, 0x0000);
-}
-
-static void
-awe_update_chorus_mode(void)
-{
-	awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]);
-}
-
-/*----------------------------------------------------------------*/
-
-/* reverb mode settings; write the following 28 data of 16 bit length
- *   on the corresponding ports in the reverb_cmds array
- */
-static char reverb_defined[AWE_CHORUS_NUMBERS];
-static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = {
-{{  /* room 1 */
-	0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
-	0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
-	0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* room 2 */
-	0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
-	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
-	0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* room 3 */
-	0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
-	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
-	0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
-	0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
-}},
-{{  /* hall 1 */
-	0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
-	0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
-	0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
-	0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
-}},
-{{  /* hall 2 */
-	0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
-	0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
-	0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* plate */
-	0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
-	0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
-	0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
-	0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{  /* delay */
-	0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
-	0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
-	0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
-	0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-{{  /* panning delay */
-	0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
-	0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
-	0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
-	0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-};
-
-static struct ReverbCmdPair {
-	unsigned short cmd, port;
-} reverb_cmds[28] = {
-  {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
-  {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
-  {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
-  {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
-  {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
-  {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
-  {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
-};
-
-static int
-awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count)
-{
-	if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
-		printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg);
-		return -EINVAL;
-	}
-	if (count < sizeof(awe_reverb_fx_rec)) {
-		printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n");
-		return -EINVAL;
-	}
-	if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
-			   sizeof(awe_reverb_fx_rec)))
-		return -EFAULT;
-	reverb_defined[patch->optarg] = TRUE;
-	return 0;
-}
-
-static void
-awe_set_reverb_mode(int effect)
-{
-	int i;
-	if (effect < 0 || effect >= AWE_REVERB_NUMBERS ||
-	    (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect]))
-		return;
-	for (i = 0; i < 28; i++)
-		awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port,
-			 reverb_parm[effect].parms[i]);
-}
-
-static void
-awe_update_reverb_mode(void)
-{
-	awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
-}
-
-/*
- * treble/bass equalizer control
- */
-
-static unsigned short bass_parm[12][3] = {
-	{0xD26A, 0xD36A, 0x0000}, /* -12 dB */
-	{0xD25B, 0xD35B, 0x0000}, /*  -8 */
-	{0xD24C, 0xD34C, 0x0000}, /*  -6 */
-	{0xD23D, 0xD33D, 0x0000}, /*  -4 */
-	{0xD21F, 0xD31F, 0x0000}, /*  -2 */
-	{0xC208, 0xC308, 0x0001}, /*   0 (HW default) */
-	{0xC219, 0xC319, 0x0001}, /*  +2 */
-	{0xC22A, 0xC32A, 0x0001}, /*  +4 */
-	{0xC24C, 0xC34C, 0x0001}, /*  +6 */
-	{0xC26E, 0xC36E, 0x0001}, /*  +8 */
-	{0xC248, 0xC348, 0x0002}, /* +10 */
-	{0xC26A, 0xC36A, 0x0002}, /* +12 dB */
-};
-
-static unsigned short treble_parm[12][9] = {
-	{0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
-	{0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-	{0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-	{0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-	{0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
-	{0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
-	{0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
-	{0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
-	{0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
-	{0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
-	{0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
-	{0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */
-};
-
-
-/*
- * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
- */
-static void
-awe_equalizer(int bass, int treble)
-{
-	unsigned short w;
-
-	if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
-		return;
-	awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]);
-	awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]);
-	awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]);
-	awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]);
-	awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]);
-	awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]);
-	awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]);
-	awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]);
-	awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]);
-	awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]);
-	w = bass_parm[bass][2] + treble_parm[treble][8];
-	awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262));
-	awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362));
-}
-
-static void awe_update_equalizer(void)
-{
-	awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]);
-}
-
-
-/*----------------------------------------------------------------*/
-
-#ifdef CONFIG_AWE32_MIDIEMU
-
-/*
- * Emu8000 MIDI Emulation
- */
-
-/*
- * midi queue record
- */
-
-/* queue type */
-enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
-
-#define MAX_MIDIBUF	64
-
-/* midi status */
-typedef struct MidiStatus {
-	int queue;	/* queue type */
-	int qlen;	/* queue length */
-	int read;	/* chars read */
-	int status;	/* current status */
-	int chan;	/* current channel */
-	unsigned char buf[MAX_MIDIBUF];
-} MidiStatus;
-
-/* MIDI mode type */
-enum { MODE_GM, MODE_GS, MODE_XG, };
-
-/* NRPN / CC -> Emu8000 parameter converter */
-typedef struct {
-	int control;
-	int awe_effect;
-	unsigned short (*convert)(int val);
-} ConvTable;
-
-
-/*
- * prototypes
- */
-
-static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
-static void awe_midi_close(int dev);
-static int awe_midi_ioctl(int dev, unsigned cmd, void __user * arg);
-static int awe_midi_outputc(int dev, unsigned char midi_byte);
-
-static void init_midi_status(MidiStatus *st);
-static void clear_rpn(void);
-static void get_midi_char(MidiStatus *st, int c);
-/*static void queue_varlen(MidiStatus *st, int c);*/
-static void special_event(MidiStatus *st, int c);
-static void queue_read(MidiStatus *st, int c);
-static void midi_note_on(MidiStatus *st);
-static void midi_note_off(MidiStatus *st);
-static void midi_key_pressure(MidiStatus *st);
-static void midi_channel_pressure(MidiStatus *st);
-static void midi_pitch_wheel(MidiStatus *st);
-static void midi_program_change(MidiStatus *st);
-static void midi_control_change(MidiStatus *st);
-static void midi_select_bank(MidiStatus *st, int val);
-static void midi_nrpn_event(MidiStatus *st);
-static void midi_rpn_event(MidiStatus *st);
-static void midi_detune(int chan, int coarse, int fine);
-static void midi_system_exclusive(MidiStatus *st);
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int xg_control_change(MidiStatus *st, int cmd, int val);
-
-#define numberof(ary)	(sizeof(ary)/sizeof(ary[0]))
-
-
-/*
- * OSS Midi device record
- */
-
-static struct midi_operations awe_midi_operations =
-{
-	.owner		= THIS_MODULE,
-	.info		= {"AWE Midi Emu", 0, 0, SNDCARD_SB},
-	.in_info	= {0},
-	.open		= awe_midi_open, /*open*/
-	.close		= awe_midi_close, /*close*/
-	.ioctl		= awe_midi_ioctl, /*ioctl*/
-	.outputc	= awe_midi_outputc, /*outputc*/
-};
-
-static int my_mididev = -1;
-
-static void __init attach_midiemu(void)
-{
-	if ((my_mididev = sound_alloc_mididev()) < 0)
-		printk ("Sound: Too many midi devices detected\n");
-	else
-		midi_devs[my_mididev] = &awe_midi_operations;
-}
-
-static void unload_midiemu(void)
-{
-	if (my_mididev >= 0)
-		sound_unload_mididev(my_mididev);
-}
-
-
-/*
- * open/close midi device
- */
-
-static int midi_opened = FALSE;
-
-static int midi_mode;
-static int coarsetune, finetune;
-
-static int xg_mapping = TRUE;
-static int xg_bankmode;
-
-/* effect sensitivity */
-
-#define FX_CUTOFF	0
-#define FX_RESONANCE	1
-#define FX_ATTACK	2
-#define FX_RELEASE	3
-#define FX_VIBRATE	4
-#define FX_VIBDEPTH	5
-#define FX_VIBDELAY	6
-#define FX_NUMS		7
-
-#define DEF_FX_CUTOFF		170
-#define DEF_FX_RESONANCE	6
-#define DEF_FX_ATTACK		50
-#define DEF_FX_RELEASE		50
-#define DEF_FX_VIBRATE		30
-#define DEF_FX_VIBDEPTH		4
-#define DEF_FX_VIBDELAY		1500
-
-/* effect sense: */
-static int gs_sense[] = 
-{
-	DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
-	DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-static int xg_sense[] = 
-{
-	DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
-	DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-
-
-/* current status */
-static MidiStatus curst;
-
-
-static int
-awe_midi_open (int dev, int mode,
-	       void (*input)(int,unsigned char),
-	       void (*output)(int))
-{
-	if (midi_opened)
-		return -EBUSY;
-
-	midi_opened = TRUE;
-
-	midi_mode = MODE_GM;
-
-	curst.queue = Q_NONE;
-	curst.qlen = 0;
-	curst.read = 0;
-	curst.status = 0;
-	curst.chan = 0;
-	memset(curst.buf, 0, sizeof(curst.buf));
-
-	init_midi_status(&curst);
-
-	return 0;
-}
-
-static void
-awe_midi_close (int dev)
-{
-	midi_opened = FALSE;
-}
-
-
-static int
-awe_midi_ioctl (int dev, unsigned cmd, void __user *arg)
-{
-	return -EPERM;
-}
-
-static int
-awe_midi_outputc (int dev, unsigned char midi_byte)
-{
-	if (! midi_opened)
-		return 1;
-
-	/* force to change playing mode */
-	playing_mode = AWE_PLAY_MULTI;
-
-	get_midi_char(&curst, midi_byte);
-	return 1;
-}
-
-
-/*
- * initialize
- */
-
-static void init_midi_status(MidiStatus *st)
-{
-	clear_rpn();
-	coarsetune = 0;
-	finetune = 0;
-}
-
-
-/*
- * RPN & NRPN
- */
-
-#define MAX_MIDI_CHANNELS	16
-
-/* RPN & NRPN */
-static unsigned char nrpn[MAX_MIDI_CHANNELS];  /* current event is NRPN? */
-static int msb_bit;  /* current event is msb for RPN/NRPN */
-/* RPN & NRPN indeces */
-static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS];
-/* RPN & NRPN values */
-static int rpn_val[MAX_MIDI_CHANNELS];
-
-static void clear_rpn(void)
-{
-	int i;
-	for (i = 0; i < MAX_MIDI_CHANNELS; i++) {
-		nrpn[i] = 0;
-		rpn_msb[i] = 127;
-		rpn_lsb[i] = 127;
-		rpn_val[i] = 0;
-	}
-	msb_bit = 0;
-}
-
-
-/*
- * process midi queue
- */
-
-/* status event types */
-typedef void (*StatusEvent)(MidiStatus *st);
-static struct StatusEventList {
-	StatusEvent process;
-	int qlen;
-} status_event[8] = {
-	{midi_note_off, 2},
-	{midi_note_on, 2},
-	{midi_key_pressure, 2},
-	{midi_control_change, 2},
-	{midi_program_change, 1},
-	{midi_channel_pressure, 1},
-	{midi_pitch_wheel, 2},
-	{NULL, 0},
-};
-
-
-/* read a char from fifo and process it */
-static void get_midi_char(MidiStatus *st, int c)
-{
-	if (c == 0xfe) {
-		/* ignore active sense */
-		st->queue = Q_NONE;
-		return;
-	}
-
-	switch (st->queue) {
-	/* case Q_VARLEN: queue_varlen(st, c); break;*/
-	case Q_READ:
-	case Q_SYSEX:
-		queue_read(st, c);
-		break;
-	case Q_NONE:
-		st->read = 0;
-		if ((c & 0xf0) == 0xf0) {
-			special_event(st, c);
-		} else if (c & 0x80) { /* status change */
-			st->status = (c >> 4) & 0x07;
-			st->chan = c & 0x0f;
-			st->queue = Q_READ;
-			st->qlen = status_event[st->status].qlen;
-			if (st->qlen == 0)
-				st->queue = Q_NONE;
-		}
-		break;
-	}
-}
-
-/* 0xfx events */
-static void special_event(MidiStatus *st, int c)
-{
-	switch (c) {
-	case 0xf0: /* system exclusive */
-		st->queue = Q_SYSEX;
-		st->qlen = 0;
-		break;
-	case 0xf1: /* MTC quarter frame */
-	case 0xf3: /* song select */
-		st->queue = Q_READ;
-		st->qlen = 1;
-		break;
-	case 0xf2: /* song position */
-		st->queue = Q_READ;
-		st->qlen = 2;
-		break;
-	}
-}
-
-#if 0
-/* read variable length value */
-static void queue_varlen(MidiStatus *st, int c)
-{
-	st->qlen += (c & 0x7f);
-	if (c & 0x80) {
-		st->qlen <<= 7;
-		return;
-	}
-	if (st->qlen <= 0) {
-		st->qlen = 0;
-		st->queue = Q_NONE;
-	}
-	st->queue = Q_READ;
-	st->read = 0;
-}
-#endif
-
-
-/* read a char */
-static void queue_read(MidiStatus *st, int c)
-{
-	if (st->read < MAX_MIDIBUF) {
-		if (st->queue != Q_SYSEX)
-			c &= 0x7f;
-		st->buf[st->read] = (unsigned char)c;
-	}
-	st->read++;
-	if (st->queue == Q_SYSEX && c == 0xf7) {
-		midi_system_exclusive(st);
-		st->queue = Q_NONE;
-	} else if (st->queue == Q_READ && st->read >= st->qlen) {
-		if (status_event[st->status].process)
-			status_event[st->status].process(st);
-		st->queue = Q_NONE;
-	}
-}
-
-
-/*
- * status events
- */
-
-/* note on */
-static void midi_note_on(MidiStatus *st)
-{
-	DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
-	if (st->buf[1] == 0)
-		midi_note_off(st);
-	else
-		awe_start_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* note off */
-static void midi_note_off(MidiStatus *st)
-{
-	DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
-	awe_kill_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* key pressure change */
-static void midi_key_pressure(MidiStatus *st)
-{
-	awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* channel pressure change */
-static void midi_channel_pressure(MidiStatus *st)
-{
-	channels[st->chan].chan_press = st->buf[0];
-	awe_modwheel_change(st->chan, st->buf[0]);
-}
-
-/* pitch wheel change */
-static void midi_pitch_wheel(MidiStatus *st)
-{
-	int val = (int)st->buf[1] * 128 + st->buf[0];
-	awe_bender(0, st->chan, val);
-}
-
-/* program change */
-static void midi_program_change(MidiStatus *st)
-{
-	int preset;
-	preset = st->buf[0];
-	if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127)
-		preset = 0;
-	else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan))
-		preset += 64;
-
-	awe_set_instr(0, st->chan, preset);
-}
-
-#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val)
-#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val)
-#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0)
-
-/* midi control change */
-static void midi_control_change(MidiStatus *st)
-{
-	int cmd = st->buf[0];
-	int val = st->buf[1];
-
-	DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val));
-	if (midi_mode == MODE_XG) {
-		if (xg_control_change(st, cmd, val))
-			return;
-	}
-
-	/* controls #31 - #64 are LSB of #0 - #31 */
-	msb_bit = 1;
-	if (cmd >= 0x20 && cmd < 0x40) {
-		msb_bit = 0;
-		cmd -= 0x20;
-	}
-
-	switch (cmd) {
-	case CTL_SOFT_PEDAL:
-		if (val == 127)
-			add_effect(st->chan, AWE_FX_CUTOFF, -160);
-		else
-			unset_effect(st->chan, AWE_FX_CUTOFF);
-		break;
-
-	case CTL_BANK_SELECT:
-		midi_select_bank(st, val);
-		break;
-		
-	/* set RPN/NRPN parameter */
-	case CTL_REGIST_PARM_NUM_MSB:
-		nrpn[st->chan]=0; rpn_msb[st->chan]=val;
-		break;
-	case CTL_REGIST_PARM_NUM_LSB:
-		nrpn[st->chan]=0; rpn_lsb[st->chan]=val;
-		break;
-	case CTL_NONREG_PARM_NUM_MSB:
-		nrpn[st->chan]=1; rpn_msb[st->chan]=val;
-		break;
-	case CTL_NONREG_PARM_NUM_LSB:
-		nrpn[st->chan]=1; rpn_lsb[st->chan]=val;
-		break;
-
-	/* send RPN/NRPN entry */
-	case CTL_DATA_ENTRY:
-		if (msb_bit)
-			rpn_val[st->chan] = val * 128;
-		else
-			rpn_val[st->chan] |= val;
-		if (nrpn[st->chan])
-			midi_nrpn_event(st);
-		else
-			midi_rpn_event(st);
-		break;
-
-	/* increase/decrease data entry */
-	case CTL_DATA_INCREMENT:
-		rpn_val[st->chan]++;
-		midi_rpn_event(st);
-		break;
-	case CTL_DATA_DECREMENT:
-		rpn_val[st->chan]--;
-		midi_rpn_event(st);
-		break;
-
-	/* default */
-	default:
-		awe_controller(0, st->chan, cmd, val);
-		break;
-	}
-}
-
-/* tone bank change */
-static void midi_select_bank(MidiStatus *st, int val)
-{
-	if (midi_mode == MODE_XG && msb_bit) {
-		xg_bankmode = val;
-		/* XG MSB value; not normal bank selection */
-		switch (val) {
-		case 127: /* remap to drum channel */
-			awe_controller(0, st->chan, CTL_BANK_SELECT, 128);
-			break;
-		default: /* remap to normal channel */
-			awe_controller(0, st->chan, CTL_BANK_SELECT, val);
-			break;
-		}
-		return;
-	} else if (midi_mode == MODE_GS && !msb_bit)
-		/* ignore LSB bank in GS mode (used for mapping) */
-		return;
-
-	/* normal bank controls; accept both MSB and LSB */
-	if (! IS_DRUM_CHANNEL(st->chan)) {
-		if (midi_mode == MODE_XG) {
-			if (xg_bankmode) return;
-			if (val == 64 || val == 126)
-				val = 0;
-		} else if (midi_mode == MODE_GS && val == 127)
-			val = 0;
-		awe_controller(0, st->chan, CTL_BANK_SELECT, val);
-	}
-}
-
-
-/*
- * RPN events
- */
-
-static void midi_rpn_event(MidiStatus *st)
-{
-	int type;
-	type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan];
-	switch (type) {
-	case 0x0000: /* Pitch bend sensitivity */
-		/* MSB only / 1 semitone per 128 */
-		if (msb_bit) {
-			channels[st->chan].bender_range = 
-				rpn_val[st->chan] * 100 / 128;
-		}
-		break;
-					
-	case 0x0001: /* fine tuning: */
-		/* MSB/LSB, 8192=center, 100/8192 cent step */
-		finetune = rpn_val[st->chan] - 8192;
-		midi_detune(st->chan, coarsetune, finetune);
-		break;
-
-	case 0x0002: /* coarse tuning */
-		/* MSB only / 8192=center, 1 semitone per 128 */
-		if (msb_bit) {
-			coarsetune = rpn_val[st->chan] - 8192;
-			midi_detune(st->chan, coarsetune, finetune);
-		}
-		break;
-
-	case 0x7F7F: /* "lock-in" RPN */
-		break;
-	}
-}
-
-
-/* tuning:
- *   coarse = -8192 to 8192 (100 cent per 128)
- *   fine = -8192 to 8192 (max=100cent)
- */
-static void midi_detune(int chan, int coarse, int fine)
-{
-	/* 4096 = 1200 cents in AWE parameter */
-	int val;
-	val = coarse * 4096 / (12 * 128);
-	val += fine / 24;
-	if (val)
-		send_effect(chan, AWE_FX_INIT_PITCH, val);
-	else
-		unset_effect(chan, AWE_FX_INIT_PITCH);
-}
-
-
-/*
- * system exclusive message
- * GM/GS/XG macros are accepted
- */
-
-static void midi_system_exclusive(MidiStatus *st)
-{
-	/* GM on */
-	static unsigned char gm_on_macro[] = {
-		0x7e,0x7f,0x09,0x01,
-	};
-	/* XG on */
-	static unsigned char xg_on_macro[] = {
-		0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
-	};
-	/* GS prefix
-	 * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off
-	 * reverb mode: XX=0x01, YY=0x30, ZZ=0-7
-	 * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
-	 */
-	static unsigned char gs_pfx_macro[] = {
-		0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
-	};
-
-#if 0
-	/* SC88 system mode set
-	 * single module mode: XX=1
-	 * double module mode: XX=0
-	 */
-	static unsigned char gs_mode_macro[] = {
-		0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/
-	};
-	/* SC88 display macro: XX=01:bitmap, 00:text
-	 */
-	static unsigned char gs_disp_macro[] = {
-		0x41,0x10,0x45,0x12,0x10,/*XX,00*/
-	};
-#endif
-
-	/* GM on */
-	if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
-		if (midi_mode != MODE_GS && midi_mode != MODE_XG)
-			midi_mode = MODE_GM;
-		init_midi_status(st);
-	}
-
-	/* GS macros */
-	else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
-		if (midi_mode != MODE_GS && midi_mode != MODE_XG)
-			midi_mode = MODE_GS;
-
-		if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) {
-			/* GS reset */
-			init_midi_status(st);
-		}
-
-		else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) {
-			/* drum pattern */
-			int p = st->buf[5] & 0x0f;
-			if (p == 0) p = 9;
-			else if (p < 10) p--;
-			if (st->buf[7] == 0)
-				DRUM_CHANNEL_OFF(p);
-			else
-				DRUM_CHANNEL_ON(p);
-
-		} else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) {
-			/* program */
-			int p = st->buf[5] & 0x0f;
-			if (p == 0) p = 9;
-			else if (p < 10) p--;
-			if (! IS_DRUM_CHANNEL(p))
-				awe_set_instr(0, p, st->buf[7]);
-
-		} else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) {
-			/* reverb mode */
-			awe_set_reverb_mode(st->buf[7]);
-
-		} else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) {
-			/* chorus mode */
-			awe_set_chorus_mode(st->buf[7]);
-
-		} else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) {
-			/* master volume */
-			awe_change_master_volume(st->buf[7]);
-
-		}
-	}
-
-	/* XG on */
-	else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
-		midi_mode = MODE_XG;
-		xg_mapping = TRUE;
-		xg_bankmode = 0;
-	}
-}
-
-
-/*----------------------------------------------------------------*/
-
-/*
- * convert NRPN/control values
- */
-
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
-	int i, cval;
-	for (i = 0; i < num_tables; i++) {
-		if (table[i].control == type) {
-			cval = table[i].convert(val);
-			send_effect(st->chan, table[i].awe_effect, cval);
-			return TRUE;
-		}
-	}
-	return FALSE;
-}
-
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
-	int i, cval;
-	for (i = 0; i < num_tables; i++) {
-		if (table[i].control == type) {
-			cval = table[i].convert(val);
-			add_effect(st->chan, table[i].awe_effect|0x80, cval);
-			return TRUE;
-		}
-	}
-	return FALSE;
-}
-
-
-/*
- * AWE32 NRPN effects
- */
-
-static unsigned short fx_delay(int val);
-static unsigned short fx_attack(int val);
-static unsigned short fx_hold(int val);
-static unsigned short fx_decay(int val);
-static unsigned short fx_the_value(int val);
-static unsigned short fx_twice_value(int val);
-static unsigned short fx_conv_pitch(int val);
-static unsigned short fx_conv_Q(int val);
-
-/* function for each NRPN */		/* [range]  units */
-#define fx_env1_delay	fx_delay	/* [0,5900] 4msec */
-#define fx_env1_attack	fx_attack	/* [0,5940] 1msec */
-#define fx_env1_hold	fx_hold		/* [0,8191] 1msec */
-#define fx_env1_decay	fx_decay	/* [0,5940] 4msec */
-#define fx_env1_release	fx_decay	/* [0,5940] 4msec */
-#define fx_env1_sustain	fx_the_value	/* [0,127] 0.75dB */
-#define fx_env1_pitch	fx_the_value	/* [-127,127] 9.375cents */
-#define fx_env1_cutoff	fx_the_value	/* [-127,127] 56.25cents */
-
-#define fx_env2_delay	fx_delay	/* [0,5900] 4msec */
-#define fx_env2_attack	fx_attack	/* [0,5940] 1msec */
-#define fx_env2_hold	fx_hold		/* [0,8191] 1msec */
-#define fx_env2_decay	fx_decay	/* [0,5940] 4msec */
-#define fx_env2_release	fx_decay	/* [0,5940] 4msec */
-#define fx_env2_sustain	fx_the_value	/* [0,127] 0.75dB */
-
-#define fx_lfo1_delay	fx_delay	/* [0,5900] 4msec */
-#define fx_lfo1_freq	fx_twice_value	/* [0,127] 84mHz */
-#define fx_lfo1_volume	fx_twice_value	/* [0,127] 0.1875dB */
-#define fx_lfo1_pitch	fx_the_value	/* [-127,127] 9.375cents */
-#define fx_lfo1_cutoff	fx_twice_value	/* [-64,63] 56.25cents */
-
-#define fx_lfo2_delay	fx_delay	/* [0,5900] 4msec */
-#define fx_lfo2_freq	fx_twice_value	/* [0,127] 84mHz */
-#define fx_lfo2_pitch	fx_the_value	/* [-127,127] 9.375cents */
-
-#define fx_init_pitch	fx_conv_pitch	/* [-8192,8192] cents */
-#define fx_chorus	fx_the_value	/* [0,255] -- */
-#define fx_reverb	fx_the_value	/* [0,255] -- */
-#define fx_cutoff	fx_twice_value	/* [0,127] 62Hz */
-#define fx_filterQ	fx_conv_Q	/* [0,127] -- */
-
-static unsigned short fx_delay(int val)
-{
-	return (unsigned short)calc_parm_delay(val);
-}
-
-static unsigned short fx_attack(int val)
-{
-	return (unsigned short)calc_parm_attack(val);
-}
-
-static unsigned short fx_hold(int val)
-{
-	return (unsigned short)calc_parm_hold(val);
-}
-
-static unsigned short fx_decay(int val)
-{
-	return (unsigned short)calc_parm_decay(val);
-}
-
-static unsigned short fx_the_value(int val)
-{
-	return (unsigned short)(val & 0xff);
-}
-
-static unsigned short fx_twice_value(int val)
-{
-	return (unsigned short)((val * 2) & 0xff);
-}
-
-static unsigned short fx_conv_pitch(int val)
-{
-	return (short)(val * 4096 / 1200);
-}
-
-static unsigned short fx_conv_Q(int val)
-{
-	return (unsigned short)((val / 8) & 0xff);
-}
-
-
-static ConvTable awe_effects[] =
-{
-	{ 0, AWE_FX_LFO1_DELAY,	fx_lfo1_delay},
-	{ 1, AWE_FX_LFO1_FREQ,	fx_lfo1_freq},
-	{ 2, AWE_FX_LFO2_DELAY,	fx_lfo2_delay},
-	{ 3, AWE_FX_LFO2_FREQ,	fx_lfo2_freq},
-
-	{ 4, AWE_FX_ENV1_DELAY,	fx_env1_delay},
-	{ 5, AWE_FX_ENV1_ATTACK,fx_env1_attack},
-	{ 6, AWE_FX_ENV1_HOLD,	fx_env1_hold},
-	{ 7, AWE_FX_ENV1_DECAY,	fx_env1_decay},
-	{ 8, AWE_FX_ENV1_SUSTAIN,	fx_env1_sustain},
-	{ 9, AWE_FX_ENV1_RELEASE,	fx_env1_release},
-
-	{10, AWE_FX_ENV2_DELAY,	fx_env2_delay},
-	{11, AWE_FX_ENV2_ATTACK,	fx_env2_attack},
-	{12, AWE_FX_ENV2_HOLD,	fx_env2_hold},
-	{13, AWE_FX_ENV2_DECAY,	fx_env2_decay},
-	{14, AWE_FX_ENV2_SUSTAIN,	fx_env2_sustain},
-	{15, AWE_FX_ENV2_RELEASE,	fx_env2_release},
-
-	{16, AWE_FX_INIT_PITCH,	fx_init_pitch},
-	{17, AWE_FX_LFO1_PITCH,	fx_lfo1_pitch},
-	{18, AWE_FX_LFO2_PITCH,	fx_lfo2_pitch},
-	{19, AWE_FX_ENV1_PITCH,	fx_env1_pitch},
-	{20, AWE_FX_LFO1_VOLUME,	fx_lfo1_volume},
-	{21, AWE_FX_CUTOFF,		fx_cutoff},
-	{22, AWE_FX_FILTERQ,	fx_filterQ},
-	{23, AWE_FX_LFO1_CUTOFF,	fx_lfo1_cutoff},
-	{24, AWE_FX_ENV1_CUTOFF,	fx_env1_cutoff},
-	{25, AWE_FX_CHORUS,		fx_chorus},
-	{26, AWE_FX_REVERB,		fx_reverb},
-};
-
-static int num_awe_effects = numberof(awe_effects);
-
-
-/*
- * GS(SC88) NRPN effects; still experimental
- */
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short gs_cutoff(int val)
-{
-	return (val - 64) * gs_sense[FX_CUTOFF] / 50;
-}
-
-/* resonance: 0 to 15(max) */
-static unsigned short gs_filterQ(int val)
-{
-	return (val - 64) * gs_sense[FX_RESONANCE] / 50;
-}
-
-/* attack: */
-static unsigned short gs_attack(int val)
-{
-	return -(val - 64) * gs_sense[FX_ATTACK] / 50;
-}
-
-/* decay: */
-static unsigned short gs_decay(int val)
-{
-	return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* release: */
-static unsigned short gs_release(int val)
-{
-	return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* vibrato freq: 0.042Hz step, max=255 */
-static unsigned short gs_vib_rate(int val)
-{
-	return (val - 64) * gs_sense[FX_VIBRATE] / 50;
-}
-
-/* vibrato depth: max=127, 1 octave */
-static unsigned short gs_vib_depth(int val)
-{
-	return (val - 64) * gs_sense[FX_VIBDEPTH] / 50;
-}
-
-/* vibrato delay: -0.725msec step */
-static unsigned short gs_vib_delay(int val)
-{
-	return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
-}
-
-static ConvTable gs_effects[] =
-{
-	{32, AWE_FX_CUTOFF,	gs_cutoff},
-	{33, AWE_FX_FILTERQ,	gs_filterQ},
-	{99, AWE_FX_ENV2_ATTACK, gs_attack},
-	{100, AWE_FX_ENV2_DECAY, gs_decay},
-	{102, AWE_FX_ENV2_RELEASE, gs_release},
-	{8, AWE_FX_LFO1_FREQ, gs_vib_rate},
-	{9, AWE_FX_LFO1_VOLUME, gs_vib_depth},
-	{10, AWE_FX_LFO1_DELAY, gs_vib_delay},
-};
-
-static int num_gs_effects = numberof(gs_effects);
-
-
-/*
- * NRPN events: accept as AWE32/SC88 specific controls
- */
-
-static void midi_nrpn_event(MidiStatus *st)
-{
-	if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) {
-		if (! msb_bit) /* both MSB/LSB necessary */
-			send_converted_effect(awe_effects, num_awe_effects,
-					      st, rpn_lsb[st->chan],
-					      rpn_val[st->chan] - 8192);
-	} else if (rpn_msb[st->chan] == 1) {
-		if (msb_bit) /* only MSB is valid */
-			add_converted_effect(gs_effects, num_gs_effects,
-					     st, rpn_lsb[st->chan],
-					     rpn_val[st->chan] / 128);
-	}
-}
-
-
-/*
- * XG control effects; still experimental
- */
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short xg_cutoff(int val)
-{
-	return (val - 64) * xg_sense[FX_CUTOFF] / 64;
-}
-
-/* resonance: 0(open) to 15(most nasal) */
-static unsigned short xg_filterQ(int val)
-{
-	return (val - 64) * xg_sense[FX_RESONANCE] / 64;
-}
-
-/* attack: */
-static unsigned short xg_attack(int val)
-{
-	return -(val - 64) * xg_sense[FX_ATTACK] / 64;
-}
-
-/* release: */
-static unsigned short xg_release(int val)
-{
-	return -(val - 64) * xg_sense[FX_RELEASE] / 64;
-}
-
-static ConvTable xg_effects[] =
-{
-	{71, AWE_FX_CUTOFF,	xg_cutoff},
-	{74, AWE_FX_FILTERQ,	xg_filterQ},
-	{72, AWE_FX_ENV2_RELEASE, xg_release},
-	{73, AWE_FX_ENV2_ATTACK, xg_attack},
-};
-
-static int num_xg_effects = numberof(xg_effects);
-
-static int xg_control_change(MidiStatus *st, int cmd, int val)
-{
-	return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val);
-}
-
-#endif /* CONFIG_AWE32_MIDIEMU */
-
-
-/*----------------------------------------------------------------*/
-
-
-/*
- * initialization of AWE driver
- */
-
-static void
-awe_initialize(void)
-{
-	DEBUG(0,printk("AWE32: initializing..\n"));
-
-	/* initialize hardware configuration */
-	awe_poke(AWE_HWCF1, 0x0059);
-	awe_poke(AWE_HWCF2, 0x0020);
-
-	/* disable audio; this seems to reduce a clicking noise a bit.. */
-	awe_poke(AWE_HWCF3, 0);
-
-	/* initialize audio channels */
-	awe_init_audio();
-
-	/* initialize DMA */
-	awe_init_dma();
-
-	/* initialize init array */
-	awe_init_array();
-
-	/* check DRAM memory size */
-	awe_check_dram();
-
-	/* initialize the FM section of the AWE32 */
-	awe_init_fm();
-
-	/* set up voice envelopes */
-	awe_tweak();
-
-	/* enable audio */
-	awe_poke(AWE_HWCF3, 0x0004);
-
-	/* set default values */
-	awe_init_ctrl_parms(TRUE);
-
-	/* set equalizer */
-	awe_update_equalizer();
-
-	/* set reverb & chorus modes */
-	awe_update_reverb_mode();
-	awe_update_chorus_mode();
-}
-
-
-/*
- * Core Device Management Functions
- */
-
-/* store values to i/o port array */
-static void setup_ports(int port1, int port2, int port3)
-{
-	awe_ports[0] = port1;
-	if (port2 == 0)
-		port2 = port1 + 0x400;
-	awe_ports[1] = port2;
-	awe_ports[2] = port2 + 2;
-	if (port3 == 0)
-		port3 = port1 + 0x800;
-	awe_ports[3] = port3;
-	awe_ports[4] = port3 + 2;
-
-	port_setuped = TRUE;
-}
-
-/*
- * port request
- *  0x620-623, 0xA20-A23, 0xE20-E23
- */
-
-static int
-awe_request_region(void)
-{
-	if (! port_setuped)
-		return 0;
-	if (! request_region(awe_ports[0], 4, "sound driver (AWE32)"))
-		return 0;
-	if (! request_region(awe_ports[1], 4, "sound driver (AWE32)"))
-		goto err_out;
-	if (! request_region(awe_ports[3], 4, "sound driver (AWE32)"))
-		goto err_out1;
-	return 1;
-err_out1:
-	release_region(awe_ports[1], 4);
-err_out:
-	release_region(awe_ports[0], 4);
-	return 0;
-}
-
-static void
-awe_release_region(void)
-{
-	if (! port_setuped) return;
-	release_region(awe_ports[0], 4);
-	release_region(awe_ports[1], 4);
-	release_region(awe_ports[3], 4);
-}
-
-static int awe_attach_device(void)
-{
-	if (awe_present) return 0; /* for OSS38.. called twice? */
-
-	/* reserve I/O ports for awedrv */
-	if (! awe_request_region()) {
-		printk(KERN_ERR "AWE32: I/O area already used.\n");
-		return 0;
-	}
-
-	/* set buffers to NULL */
-	sfhead = sftail = NULL;
-
-	my_dev = sound_alloc_synthdev();
-	if (my_dev == -1) {
-		printk(KERN_ERR "AWE32 Error: too many synthesizers\n");
-		awe_release_region();
-		return 0;
-	}
-
-	voice_alloc = &awe_operations.alloc;
-	voice_alloc->max_voice = awe_max_voices;
-	synth_devs[my_dev] = &awe_operations;
-
-#ifdef CONFIG_AWE32_MIXER
-	attach_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
-	attach_midiemu();
-#endif
-
-	/* clear all samples */
-	awe_reset_samples();
-
-	/* initialize AWE32 hardware */
-	awe_initialize();
-
-	sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
-		AWEDRV_VERSION, memsize/1024);
-	printk(KERN_INFO "<SoundBlaster EMU8000 (RAM%dk)>\n", memsize/1024);
-
-	awe_present = TRUE;
-
-	return 1;
-}
-
-static void awe_dettach_device(void)
-{
-	if (awe_present) {
-		awe_reset_samples();
-		awe_release_region();
-		free_tables();
-#ifdef CONFIG_AWE32_MIXER
-		unload_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
-		unload_midiemu();
-#endif
-		sound_unload_synthdev(my_dev);
-		awe_present = FALSE;
-	}
-}
-
-
-/*
- * Legacy device Probing
- */
-
-/* detect emu8000 chip on the specified address; from VV's guide */
-
-static int __init
-awe_detect_base(int addr)
-{
-	setup_ports(addr, 0, 0);
-	if ((awe_peek(AWE_U1) & 0x000F) != 0x000C)
-		return 0;
-	if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058)
-		return 0;
-	if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003)
-		return 0;
-        DEBUG(0,printk("AWE32 found at %x\n", addr));
-	return 1;
-}
-
-static int __init awe_detect_legacy_devices(void)
-{
-	int base;
-	for (base = 0x620; base <= 0x680; base += 0x20)
-		if (awe_detect_base(base)) {
-			awe_attach_device();
-			return 1;
-			}
-	DEBUG(0,printk("AWE32 Legacy detection failed\n"));
-	return 0;
-}
-
-
-/*
- * PnP device Probing
- */
-
-static struct pnp_device_id awe_pnp_ids[] = {
-	{.id = "CTL0021", .driver_data = 0}, /* AWE32 WaveTable */
-	{.id = "CTL0022", .driver_data = 0}, /* AWE64 WaveTable */
-	{.id = "CTL0023", .driver_data = 0}, /* AWE64 Gold WaveTable */
-	{ } /* terminator */
-};
-
-MODULE_DEVICE_TABLE(pnp, awe_pnp_ids);
-
-static int awe_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
-	int io1, io2, io3;
-
-	if (awe_present) {
-		printk(KERN_ERR "AWE32: This driver only supports one AWE32 device, skipping.\n");
-	}
-
-	if (!pnp_port_valid(dev,0) ||
-	    !pnp_port_valid(dev,1) ||
-	    !pnp_port_valid(dev,2)) {
-		printk(KERN_ERR "AWE32: The PnP device does not have the required resources.\n");
-		return -EINVAL;
-	}
-	io1 = pnp_port_start(dev,0);
-	io2 = pnp_port_start(dev,1);
-	io3 = pnp_port_start(dev,2);
-	printk(KERN_INFO "AWE32: A PnP Wave Table was detected at IO's %#x,%#x,%#x.\n",
-	       io1, io2, io3);
-	setup_ports(io1, io2, io3);
-
-	awe_attach_device();
-	return 0;
-}
-
-static void awe_pnp_remove(struct pnp_dev *dev)
-{
-	awe_dettach_device();
-}
-
-static struct pnp_driver awe_pnp_driver = {
-	.name		= "AWE32",
-	.id_table	= awe_pnp_ids,
-	.probe		= awe_pnp_probe,
-	.remove		= awe_pnp_remove,
-};
-
-static int __init awe_detect_pnp_devices(void)
-{
-	int ret;
-
-	ret = pnp_register_driver(&awe_pnp_driver);
-	if (ret<0)
-		printk(KERN_ERR "AWE32: PnP support is unavailable.\n");
-	return ret;
-}
-
-
-/*
- * device / lowlevel (module) interface
- */
-
-static int __init
-awe_detect(void)
-{
-	printk(KERN_INFO "AWE32: Probing for WaveTable...\n");
-	if (isapnp) {
-		if (awe_detect_pnp_devices()>=0)
-			return 1;
-	} else
-		printk(KERN_INFO "AWE32: Skipping PnP detection.\n");
-
-	if (awe_detect_legacy_devices())
-		return 1;
-
-	return 0;
-}
-
-static int __init attach_awe(void)
-{
-	return awe_detect() ? 0 : -ENODEV;
-}
-
-static void __exit unload_awe(void)
-{
-	pnp_unregister_driver(&awe_pnp_driver);
-	awe_dettach_device();
-}
-
-
-module_init(attach_awe);
-module_exit(unload_awe);
-
-#ifndef MODULE
-static int __init setup_awe(char *str)
-{
-	/* io, memsize, isapnp */
-	int ints[4];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	io = ints[1];
-	memsize = ints[2];
-	isapnp = ints[3];
-
-	return 1;
-}
-
-__setup("awe=", setup_awe);
-#endif
diff --git a/sound/oss/awe_wave.h b/sound/oss/awe_wave.h
deleted file mode 100644
index fe58481..0000000
--- a/sound/oss/awe_wave.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * sound/oss/awe_wave.h
- *
- * Configuration of AWE32/SB32/AWE64 wave table synth driver.
- *   version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * 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.
- */
-
-/*
- * chorus & reverb effects send for FM chip: from 0 to 0xff
- * larger numbers often cause weird sounds.
- */
-
-#define DEF_FM_CHORUS_DEPTH	0x10
-#define DEF_FM_REVERB_DEPTH	0x10
-
-
-/*
- * other compile conditions
- */
-
-/* initialize FM passthrough even without extended RAM */
-#undef AWE_ALWAYS_INIT_FM
-
-/* debug on */
-#define AWE_DEBUG_ON
-
-/* GUS compatible mode */
-#define AWE_HAS_GUS_COMPATIBILITY
-
-/* add MIDI emulation by wavetable */
-#define CONFIG_AWE32_MIDIEMU
-
-/* add mixer control of emu8000 equalizer */
-#undef CONFIG_AWE32_MIXER
-
-/* use new volume calculation method as default */
-#define AWE_USE_NEW_VOLUME_CALC
-
-/* check current volume target for searching empty voices */
-#define AWE_CHECK_VTARGET
-
-/* allow sample sharing */
-#define AWE_ALLOW_SAMPLE_SHARING
-
-/*
- * AWE32 card configuration:
- * uncomment the following lines *ONLY* when auto detection doesn't
- * work properly on your machine.
- */
-
-/*#define AWE_DEFAULT_BASE_ADDR	0x620*/	/* base port address */
-/*#define AWE_DEFAULT_MEM_SIZE	512*/	/* kbytes */
-
-/*
- * AWE driver version number
- */
-#define AWE_MAJOR_VERSION	0
-#define AWE_MINOR_VERSION	4
-#define AWE_TINY_VERSION	4
-#define AWE_VERSION_NUMBER	((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
-#define AWEDRV_VERSION		"0.4.4"
diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
deleted file mode 100644
index ea51aaf..0000000
--- a/sound/oss/cmpci.c
+++ /dev/null
@@ -1,3381 +0,0 @@
-/*
- *      cmpci.c  --  C-Media PCI audio driver.
- *
- *      Copyright (C) 1999  C-media support (support@cmedia.com.tw)
- *
- *      Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * 	For update, visit:
- * 		http://www.cmedia.com.tw
- *
- *      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.
- *
- * Special thanks to David C. Niemi, Jan Pfeifer
- *
- *
- * Module command line parameters:
- *   none so far
- *
- *
- *  Supported devices:
- *  /dev/dsp    standard /dev/dsp device, (mostly) OSS compatible
- *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
- *  /dev/midi   simple MIDI UART interface, no ioctl
- *
- *  The card has both an FM and a Wavetable synth, but I have to figure
- *  out first how to drive them...
- *
- *  Revision history
- *    06.05.98   0.1   Initial release
- *    10.05.98   0.2   Fixed many bugs, esp. ADC rate calculation
- *                     First stab at a simple midi interface (no bells&whistles)
- *    13.05.98   0.3   Fix stupid cut&paste error: set_adc_rate was called instead of
- *                     set_dac_rate in the FMODE_WRITE case in cm_open
- *                     Fix hwptr out of bounds (now mpg123 works)
- *    14.05.98   0.4   Don't allow excessive interrupt rates
- *    08.06.98   0.5   First release using Alan Cox' soundcore instead of miscdevice
- *    03.08.98   0.6   Do not include modversions.h
- *                     Now mixer behaviour can basically be selected between
- *                     "OSS documented" and "OSS actual" behaviour
- *    31.08.98   0.7   Fix realplayer problems - dac.count issues
- *    10.12.98   0.8   Fix drain_dac trying to wait on not yet initialized DMA
- *    16.12.98   0.9   Fix a few f_file & FMODE_ bugs
- *    06.01.99   0.10  remove the silly SA_INTERRUPT flag.
- *                     hopefully killed the egcs section type conflict
- *    12.03.99   0.11  cinfo.blocks should be reset after GETxPTR ioctl.
- *                     reported by Johan Maes <joma@telindus.be>
- *    22.03.99   0.12  return EAGAIN instead of EBUSY when O_NONBLOCK
- *                     read/write cannot be executed
- *    18.08.99   1.5   Only deallocate DMA buffer when unloading.
- *    02.09.99   1.6   Enable SPDIF LOOP
- *                     Change the mixer read back
- *    21.09.99   2.33  Use RCS version as driver version.
- *                     Add support for modem, S/PDIF loop and 4 channels.
- *                     (8738 only)
- *                     Fix bug cause x11amp cannot play.
- *
- *    Fixes:
- *    Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- *    18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
- *    		   was calling prog_dmabuf with s->lock held, call missing
- *    		   unlock_kernel in cm_midi_release
- *    08/10/2001 - use set_current_state in some more places
- *
- *	Carlos Eduardo Gorges <carlos@techlinux.com.br>
- *	Fri May 25 2001
- *	- SMP support ( spin[un]lock* revision )
- *	- speaker mixer support
- *	Mon Aug 13 2001
- *	- optimizations and cleanups
- *
- *    03/01/2003 - open_mode fixes from Georg Acher <acher@in.tum.de>
- *	Simon Braunschmidt <brasimon@web.de>
- *     Sat Jan 31 2004
- *	- provide support for opl3 FM by releasing IO range after initialization
- *
- *    ChenLi Tien <cltien@cmedia.com.tw>
- *    Mar 9 2004
- *	- Fix S/PDIF out if spdif_loop enabled
- *	- Load opl3 driver if enabled (fmio in proper range)
- *	- Load mpu401 if enabled (mpuio in proper range)
- *    Apr 5 2004
- *	- Fix DUAL_DAC dma synchronization bug
- *	- Check exist FM/MPU401 I/O before activate.
- *	- Add AFTM_S16_BE format support, so MPlayer/Xine can play AC3/mutlichannel
- *	  on Mac
- *	- Change to support kernel 2.6 so only small patch needed
- *	- All parameters default to 0
- *	- Add spdif_out to send PCM through S/PDIF out jack
- *	- Add hw_copy to get 4-spaker output for general PCM/analog output
- *
- *    Stefan Thater <stefan.thaeter@gmx.de>
- *    Apr 5 2004
- *	- Fix mute single channel for CD/Line-in/AUX-in
- */
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-#include "sound_config.h"
-#include "mpu401.h"
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
-#include "opl3.h"
-#endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-#include <linux/gameport.h>
-#include <linux/mutex.h>
-
-#endif
-
-/* --------------------------------------------------------------------- */
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#undef DMABYTEIO
-#define	DBG(x) {}
-/* --------------------------------------------------------------------- */
-
-#define CM_MAGIC  ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)
-
-/* CM8338 registers definition ****************/
-
-#define CODEC_CMI_FUNCTRL0		(0x00)
-#define CODEC_CMI_FUNCTRL1		(0x04)
-#define CODEC_CMI_CHFORMAT		(0x08)
-#define CODEC_CMI_INT_HLDCLR		(0x0C)
-#define CODEC_CMI_INT_STATUS		(0x10)
-#define CODEC_CMI_LEGACY_CTRL		(0x14)
-#define CODEC_CMI_MISC_CTRL		(0x18)
-#define CODEC_CMI_TDMA_POS		(0x1C)
-#define CODEC_CMI_MIXER			(0x20)
-#define CODEC_SB16_DATA			(0x22)
-#define CODEC_SB16_ADDR			(0x23)
-#define CODEC_CMI_MIXER1		(0x24)
-#define CODEC_CMI_MIXER2		(0x25)
-#define CODEC_CMI_AUX_VOL		(0x26)
-#define CODEC_CMI_MISC			(0x27)
-#define CODEC_CMI_AC97			(0x28)
-
-#define CODEC_CMI_CH0_FRAME1		(0x80)
-#define CODEC_CMI_CH0_FRAME2		(0x84)
-#define CODEC_CMI_CH1_FRAME1		(0x88)
-#define CODEC_CMI_CH1_FRAME2		(0x8C)
-
-#define CODEC_CMI_SPDIF_CTRL		(0x90)
-#define CODEC_CMI_MISC_CTRL2		(0x92)
-
-#define CODEC_CMI_EXT_REG		(0xF0)
-
-/*  Mixer registers for SB16 ******************/
-
-#define DSP_MIX_DATARESETIDX		((unsigned char)(0x00))
-
-#define DSP_MIX_MASTERVOLIDX_L		((unsigned char)(0x30))
-#define DSP_MIX_MASTERVOLIDX_R		((unsigned char)(0x31))
-#define DSP_MIX_VOICEVOLIDX_L		((unsigned char)(0x32))
-#define DSP_MIX_VOICEVOLIDX_R		((unsigned char)(0x33))
-#define DSP_MIX_FMVOLIDX_L		((unsigned char)(0x34))
-#define DSP_MIX_FMVOLIDX_R		((unsigned char)(0x35))
-#define DSP_MIX_CDVOLIDX_L		((unsigned char)(0x36))
-#define DSP_MIX_CDVOLIDX_R		((unsigned char)(0x37))
-#define DSP_MIX_LINEVOLIDX_L		((unsigned char)(0x38))
-#define DSP_MIX_LINEVOLIDX_R		((unsigned char)(0x39))
-
-#define DSP_MIX_MICVOLIDX		((unsigned char)(0x3A))
-#define DSP_MIX_SPKRVOLIDX		((unsigned char)(0x3B))
-
-#define DSP_MIX_OUTMIXIDX		((unsigned char)(0x3C))
-
-#define DSP_MIX_ADCMIXIDX_L		((unsigned char)(0x3D))
-#define DSP_MIX_ADCMIXIDX_R		((unsigned char)(0x3E))
-
-#define DSP_MIX_INGAINIDX_L		((unsigned char)(0x3F))
-#define DSP_MIX_INGAINIDX_R		((unsigned char)(0x40))
-#define DSP_MIX_OUTGAINIDX_L		((unsigned char)(0x41))
-#define DSP_MIX_OUTGAINIDX_R		((unsigned char)(0x42))
-
-#define DSP_MIX_AGCIDX			((unsigned char)(0x43))
-
-#define DSP_MIX_TREBLEIDX_L		((unsigned char)(0x44))
-#define DSP_MIX_TREBLEIDX_R		((unsigned char)(0x45))
-#define DSP_MIX_BASSIDX_L		((unsigned char)(0x46))
-#define DSP_MIX_BASSIDX_R		((unsigned char)(0x47))
-#define DSP_MIX_EXTENSION		((unsigned char)(0xf0))
-// pseudo register for AUX
-#define	DSP_MIX_AUXVOL_L		((unsigned char)(0x50))
-#define	DSP_MIX_AUXVOL_R		((unsigned char)(0x51))
-
-// I/O length
-#define CM_EXTENT_CODEC	  0x100
-#define CM_EXTENT_MIDI	  0x2
-#define CM_EXTENT_SYNTH	  0x4
-#define CM_EXTENT_GAME	  0x8
-
-// Function Control Register 0 (00h)
-#define CHADC0    	0x01
-#define CHADC1    	0x02
-#define PAUSE0	  	0x04
-#define PAUSE1	  	0x08
-
-// Function Control Register 0+2 (02h)
-#define CHEN0     	0x01
-#define CHEN1     	0x02
-#define RST_CH0	  	0x04
-#define RST_CH1	  	0x08
-
-// Function Control Register 1 (04h)
-#define JYSTK_EN	0x02
-#define UART_EN		0x04
-#define	SPDO2DAC	0x40
-#define	SPDFLOOP	0x80
-
-// Function Control Register 1+1 (05h)
-#define	SPDF_0		0x01
-#define	SPDF_1		0x02
-#define	ASFC		0x1c
-#define	DSFC		0xe0
-#define	SPDIF2DAC	(SPDF_1 << 8 | SPDO2DAC)
-
-// Channel Format Register (08h)
-#define CM_CFMT_STEREO	0x01
-#define CM_CFMT_16BIT	0x02
-#define CM_CFMT_MASK	0x03
-#define	POLVALID	0x20
-#define	INVSPDIFI	0x80
-
-// Channel Format Register+2 (0ah)
-#define SPD24SEL	0x20
-
-// Channel Format Register+3 (0bh)
-#define CHB3D		0x20
-#define CHB3D5C		0x80
-
-// Interrupt Hold/Clear Register+2 (0eh)
-#define	CH0_INT_EN	0x01
-#define	CH1_INT_EN	0x02
-
-// Interrupt Register (10h)
-#define CHINT0		0x01
-#define CHINT1		0x02
-#define	CH0BUSY		0x04
-#define	CH1BUSY		0x08
-
-// Legacy Control/Status Register+1 (15h)
-#define	EXBASEN		0x10
-#define	BASE2LIN	0x20
-#define	CENTR2LIN	0x40
-#define	CB2LIN		(BASE2LIN | CENTR2LIN)
-#define	CHB3D6C		0x80
-
-// Legacy Control/Status Register+2 (16h)
-#define	DAC2SPDO	0x20
-#define	SPDCOPYRHT	0x40
-#define	ENSPDOUT	0x80
-
-// Legacy Control/Status Register+3 (17h)
-#define	FMSEL		0x03
-#define	VSBSEL		0x0c
-#define	VMPU		0x60
-#define	NXCHG		0x80
-
-// Miscellaneous Control Register (18h)
-#define	REAR2LIN	0x20
-#define	MUTECH1		0x40
-#define	ENCENTER	0x80
-
-// Miscellaneous Control Register+1 (19h)
-#define	SELSPDIFI2	0x01
-#define	SPDF_AC97	0x80
-
-// Miscellaneous Control Register+2 (1ah)
-#define	AC3_EN		0x04
-#define	FM_EN		0x08
-#define	SPD32SEL	0x20
-#define	XCHGDAC		0x40
-#define	ENDBDAC		0x80
-
-// Miscellaneous Control Register+3 (1bh)
-#define	SPDIFI48K	0x01
-#define	SPDO5V		0x02
-#define	N4SPK3D		0x04
-#define	RESET		0x40
-#define	PWD		0x80
-#define	SPDIF48K	(SPDIFI48K << 24 | SPDF_AC97 << 8)
-
-// Mixer1 (24h)
-#define	CDPLAY		0x01
-#define	X3DEN		0x02
-#define	REAR2FRONT	0x10
-#define	SPK4		0x20
-#define	WSMUTE		0x40
-#define	FMMUTE		0x80
-
-// Miscellaneous Register (27h)
-#define	SPDVALID	0x02
-#define	CENTR2MIC	0x04
-
-// Miscellaneous Register2 (92h)
-#define	SPD32KFMT	0x10
-
-#define CM_CFMT_DACSHIFT   2
-#define CM_CFMT_ADCSHIFT   0
-#define CM_FREQ_DACSHIFT   5
-#define CM_FREQ_ADCSHIFT   2
-#define	RSTDAC	RST_CH1
-#define	RSTADC	RST_CH0
-#define	ENDAC	CHEN1
-#define	ENADC	CHEN0
-#define	PAUSEDAC	PAUSE1
-#define	PAUSEADC	PAUSE0
-#define CODEC_CMI_ADC_FRAME1	CODEC_CMI_CH0_FRAME1
-#define CODEC_CMI_ADC_FRAME2	CODEC_CMI_CH0_FRAME2
-#define CODEC_CMI_DAC_FRAME1	CODEC_CMI_CH1_FRAME1
-#define CODEC_CMI_DAC_FRAME2	CODEC_CMI_CH1_FRAME2
-#define	DACINT	CHINT1
-#define	ADCINT	CHINT0
-#define	DACBUSY	CH1BUSY
-#define	ADCBUSY	CH0BUSY
-#define	ENDACINT	CH1_INT_EN
-#define	ENADCINT	CH0_INT_EN
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[]	= { 0, 1, 1, 2 };
-
-#define SND_DEV_DSP16   5
-
-#define NR_DEVICE 3		/* maximum number of devices */
-
-#define	set_dac1_rate	set_adc_rate
-#define	set_dac1_rate_unlocked	set_adc_rate_unlocked
-#define	stop_dac1	stop_adc
-#define	stop_dac1_unlocked	stop_adc_unlocked
-#define	get_dmadac1	get_dmaadc
-
-static unsigned int devindex = 0;
-
-//*********************************************/
-
-struct cm_state {
-	/* magic */
-	unsigned int magic;
-
-	/* list of cmedia devices */
-	struct list_head devs;
-
-	/* the corresponding pci_dev structure */
-	struct pci_dev *dev;
-
-	int dev_audio;			/* soundcore stuff */
-	int dev_mixer;
-
-	unsigned int iosb, iobase, iosynth,
-			 iomidi, iogame, irq;	/* hardware resources */
-	unsigned short deviceid;		/* pci_id */
-
-        struct {				/* mixer stuff */
-                unsigned int modcnt;
-		unsigned short vol[13];
-        } mix;
-
-	unsigned int rateadc, ratedac;		/* wave stuff */
-	unsigned char fmt, enable;
-
-	spinlock_t lock;
-	struct mutex open_mutex;
-	mode_t open_mode;
-	wait_queue_head_t open_wait;
-
-	struct dmabuf {
-		void *rawbuf;
-		dma_addr_t dmaaddr;
-		unsigned buforder;
-		unsigned numfrag;
-		unsigned fragshift;
-		unsigned hwptr, swptr;
-		unsigned total_bytes;
-		int count;
-		unsigned error;		/* over/underrun */
-		wait_queue_head_t wait;
-
-		unsigned fragsize;	/* redundant, but makes calculations easier */
-		unsigned dmasize;
-		unsigned fragsamples;
-		unsigned dmasamples;
-
-		unsigned mapped:1;	/* OSS stuff */
-		unsigned ready:1;
-		unsigned endcleared:1;
-		unsigned enabled:1;
-		unsigned ossfragshift;
-		int ossmaxfrags;
-		unsigned subdivision;
-	} dma_dac, dma_adc;
-
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-	int midi_devc;
-	struct address_info mpu_data;
-#endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-	struct gameport *gameport;
-#endif
-
-	int	chip_version;
-	int	max_channels;
-	int	curr_channels;
-	int	capability;		/* HW capability, various for chip versions */
-
-	int	status;			/* HW or SW state */
-
-	int	spdif_counter;		/* spdif frame counter */
-};
-
-/* flags used for capability */
-#define	CAN_AC3_HW		0x00000001		/* 037 or later */
-#define	CAN_AC3_SW		0x00000002		/* 033 or later */
-#define	CAN_AC3			(CAN_AC3_HW | CAN_AC3_SW)
-#define CAN_DUAL_DAC		0x00000004		/* 033 or later */
-#define	CAN_MULTI_CH_HW		0x00000008		/* 039 or later */
-#define	CAN_MULTI_CH		(CAN_MULTI_CH_HW | CAN_DUAL_DAC)
-#define	CAN_LINE_AS_REAR	0x00000010		/* 033 or later */
-#define	CAN_LINE_AS_BASS	0x00000020		/* 039 or later */
-#define	CAN_MIC_AS_BASS		0x00000040		/* 039 or later */
-
-/* flags used for status */
-#define	DO_AC3_HW		0x00000001
-#define	DO_AC3_SW		0x00000002
-#define	DO_AC3			(DO_AC3_HW | DO_AC3_SW)
-#define	DO_DUAL_DAC		0x00000004
-#define	DO_MULTI_CH_HW		0x00000008
-#define	DO_MULTI_CH		(DO_MULTI_CH_HW | DO_DUAL_DAC)
-#define	DO_LINE_AS_REAR		0x00000010		/* 033 or later */
-#define	DO_LINE_AS_BASS		0x00000020		/* 039 or later */
-#define	DO_MIC_AS_BASS		0x00000040		/* 039 or later */
-#define	DO_SPDIF_OUT		0x00000100
-#define	DO_SPDIF_IN		0x00000200
-#define	DO_SPDIF_LOOP		0x00000400
-#define	DO_BIGENDIAN_W		0x00001000		/* used in PowerPC */
-#define	DO_BIGENDIAN_R		0x00002000		/* used in PowerPC */
-
-static LIST_HEAD(devs);
-
-static	int	mpuio;
-static	int	fmio;
-static	int	joystick;
-static	int	spdif_inverse;
-static	int	spdif_loop;
-static	int	spdif_out;
-static	int	use_line_as_rear;
-static	int	use_line_as_bass;
-static	int	use_mic_as_bass;
-static	int	mic_boost;
-static	int	hw_copy;
-module_param(mpuio, int, 0);
-module_param(fmio, int, 0);
-module_param(joystick, bool, 0);
-module_param(spdif_inverse, bool, 0);
-module_param(spdif_loop, bool, 0);
-module_param(spdif_out, bool, 0);
-module_param(use_line_as_rear, bool, 0);
-module_param(use_line_as_bass, bool, 0);
-module_param(use_mic_as_bass, bool, 0);
-module_param(mic_boost, bool, 0);
-module_param(hw_copy, bool, 0);
-MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
-MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
-MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
-MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
-MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");
-MODULE_PARM_DESC(spdif_out, "(1/0) Send PCM to S/PDIF-out (PCM volume will not function)");
-MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
-MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
-MODULE_PARM_DESC(use_mic_as_bass, "(1/0) Use mic-in jack as bass/center");
-MODULE_PARM_DESC(mic_boost, "(1/0) Enable microphone boost");
-MODULE_PARM_DESC(hw_copy, "Copy front channel to surround channel");
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned exp=16,l=5,r=0;
-	static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000};
-
-	/* num: 2, 4, 16, 256, 65536 */
-	/* exp: 1, 2,  4,   8,    16 */
-
-	while(l--) {
-		if( x >= num[l] ) {
-			if(num[l]>2) x >>= exp;
-			r+=exp;
-		}
-		exp>>=1;
-	}
-
-	return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void maskb(unsigned int addr, unsigned int mask, unsigned int value)
-{
-	outb((inb(addr) & mask) | value, addr);
-}
-
-static void maskw(unsigned int addr, unsigned int mask, unsigned int value)
-{
-	outw((inw(addr) & mask) | value, addr);
-}
-
-static void maskl(unsigned int addr, unsigned int mask, unsigned int value)
-{
-	outl((inl(addr) & mask) | value, addr);
-}
-
-static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
-{
-	if (addr)
-	    outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
-	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC0, 0);
-}
-
-static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
-{
-	outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
-	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC0);
-}
-
-static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
-{
-	outl(addr, s->iobase + CODEC_CMI_DAC_FRAME1);
-	outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, 0);
-	if (s->status & DO_DUAL_DAC)
-		set_dmadac1(s, 0, count);
-}
-
-static void set_countadc(struct cm_state *s, unsigned count)
-{
-	outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2 + 2);
-}
-
-static void set_countdac(struct cm_state *s, unsigned count)
-{
-	outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2 + 2);
-	if (s->status & DO_DUAL_DAC)
-	    set_countadc(s, count);
-}
-
-static unsigned get_dmadac(struct cm_state *s)
-{
-	unsigned int curr_addr;
-
-	curr_addr = inw(s->iobase + CODEC_CMI_DAC_FRAME2) + 1;
-	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
-	curr_addr = s->dma_dac.dmasize - curr_addr;
-
-	return curr_addr;
-}
-
-static unsigned get_dmaadc(struct cm_state *s)
-{
-	unsigned int curr_addr;
-
-	curr_addr = inw(s->iobase + CODEC_CMI_ADC_FRAME2) + 1;
-	curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
-	curr_addr = s->dma_adc.dmasize - curr_addr;
-
-	return curr_addr;
-}
-
-static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
-{
-	unsigned char regval, pseudo;
-
-	// pseudo register
-	if (idx == DSP_MIX_AUXVOL_L) {
-		data >>= 4;
-		data &= 0x0f;
-		regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0x0f;
-		outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
-		return;
-	}
-	if (idx == DSP_MIX_AUXVOL_R) {
-		data &= 0xf0;
-		regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0xf0;
-		outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
-		return;
-	}
-	outb(idx, s->iobase + CODEC_SB16_ADDR);
-	udelay(10);
-	// pseudo bits
-	if (idx == DSP_MIX_OUTMIXIDX) {
-		pseudo = data & ~0x1f;
-		pseudo >>= 1;
-		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x30;
-		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
-	}
-	if (idx == DSP_MIX_ADCMIXIDX_L) {
-		pseudo = data & 0x80;
-		pseudo >>= 1;
-		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x40;
-		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
-	}
-	if (idx == DSP_MIX_ADCMIXIDX_R) {
-		pseudo = data & 0x80;
-		regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x80;
-		outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
-	}
-	outb(data, s->iobase + CODEC_SB16_DATA);
-	udelay(10);
-}
-
-static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
-{
-	unsigned char v, pseudo;
-
-	// pseudo register
-	if (idx == DSP_MIX_AUXVOL_L) {
-		v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0x0f;
-		v <<= 4;
-		return v;
-	}
-	if (idx == DSP_MIX_AUXVOL_L) {
-		v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0xf0;
-		return v;
-	}
-	outb(idx, s->iobase + CODEC_SB16_ADDR);
-	udelay(10);
-	v = inb(s->iobase + CODEC_SB16_DATA);
-	udelay(10);
-	// pseudo bits
-	if (idx == DSP_MIX_OUTMIXIDX) {
-		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x30;
-		pseudo <<= 1;
-		v |= pseudo;
-	}
-	if (idx == DSP_MIX_ADCMIXIDX_L) {
-		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x40;
-		pseudo <<= 1;
-		v |= pseudo;
-	}
-	if (idx == DSP_MIX_ADCMIXIDX_R) {
-		pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x80;
-		v |= pseudo;
-	}
-	return v;
-}
-
-static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data)
-{
-	if (mask && s->chip_version > 0) {	/* 8338 cannot keep this */
-		s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
-		udelay(10);
-	}
-	s->fmt = (s->fmt & mask) | data;
-	outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
-	udelay(10);
-}
-
-static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	set_fmt_unlocked(s,mask,data);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data)
-{
-	outb(idx, s->iobase + CODEC_SB16_ADDR);
-	udelay(10);
-	outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);
-	udelay(10);
-}
-
-static struct {
-	unsigned	rate;
-	unsigned	lower;
-	unsigned	upper;
-	unsigned char	freq;
-} rate_lookup[] =
-{
-	{ 5512,		(0 + 5512) / 2,		(5512 + 8000) / 2,	0 },
-	{ 8000,		(5512 + 8000) / 2,	(8000 + 11025) / 2,	4 },
-	{ 11025,	(8000 + 11025) / 2,	(11025 + 16000) / 2,	1 },
-	{ 16000,	(11025 + 16000) / 2,	(16000 + 22050) / 2,	5 },
-	{ 22050,	(16000 + 22050) / 2,	(22050 + 32000) / 2,	2 },
-	{ 32000,	(22050 + 32000) / 2,	(32000 + 44100) / 2,	6 },
-	{ 44100,	(32000 + 44100) / 2,	(44100 + 48000) / 2,	3 },
-	{ 48000,	(44100 + 48000) / 2,	48000,			7 }
-};
-
-static void set_spdif_copyright(struct cm_state *s, int spdif_copyright)
-{
-	/* enable SPDIF-in Copyright */
-	maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~SPDCOPYRHT, spdif_copyright ? SPDCOPYRHT : 0);
-}
-
-static void set_spdif_loop(struct cm_state *s, int spdif_loop)
-{
-	/* enable SPDIF loop */
-	if (spdif_loop) {
-		s->status |= DO_SPDIF_LOOP;
-		/* turn on spdif-in to spdif-out */
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDFLOOP);
-	} else {
-		s->status &= ~DO_SPDIF_LOOP;
-		/* turn off spdif-in to spdif-out */
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDFLOOP, 0);
-	}
-}
-
-static void set_spdif_monitor(struct cm_state *s, int channel)
-{
-	// SPDO2DAC
-	maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDO2DAC, channel == 2 ? SPDO2DAC : 0);
-	// CDPLAY
-	if (s->chip_version >= 39)
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, channel ? CDPLAY : 0);
-}
-
-static void set_spdifout_level(struct cm_state *s, int level5v)
-{
-	/* SPDO5V */
-	if (s->chip_version > 0)
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~SPDO5V, level5v ? SPDO5V : 0);
-}
-
-static void set_spdifin_inverse(struct cm_state *s, int spdif_inverse)
-{
-	if (s->chip_version == 0)	/* 8338 has not this feature */
-		return;
-	if (spdif_inverse) {
-		/* turn on spdif-in inverse */
-		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_CHFORMAT, ~0, INVSPDIFI);
-		else
-			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
-	} else {
-		/* turn off spdif-ininverse */
-		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_CHFORMAT, ~INVSPDIFI, 0);
-		else
-			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
-	}
-}
-
-static void set_spdifin_channel2(struct cm_state *s, int channel2)
-{
-	/* SELSPDIFI2 */
-	if (s->chip_version >= 39)
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 1, ~SELSPDIFI2, channel2 ? SELSPDIFI2 : 0);
-}
-
-static void set_spdifin_valid(struct cm_state *s, int valid)
-{
-	/* SPDVALID */
-	maskb(s->iobase + CODEC_CMI_MISC, ~SPDVALID, valid ? SPDVALID : 0);
-}
-
-static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
-{
-	if (rate != 48000 && rate != 44100)
-		rate = 0;
-	if (rate == 48000 || rate == 44100) {
-		set_spdif_loop(s, 0);
-		// SPDF_1
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
-		// SPDIFI48K SPDF_AC97
-		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
-		if (s->chip_version >= 55)
-		// SPD32KFMT
-			maskb(s->iobase + CODEC_CMI_MISC_CTRL2, ~SPD32KFMT, rate == 48000 ? SPD32KFMT : 0);
-		if (s->chip_version > 0)
-		// ENSPDOUT
-			maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, ENSPDOUT);
-		// monitor SPDIF out
-		set_spdif_monitor(s, 2);
-		s->status |= DO_SPDIF_OUT;
-	} else {
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~ENSPDOUT, 0);
-		// monitor none
-		set_spdif_monitor(s, 0);
-		s->status &= ~DO_SPDIF_OUT;
-	}
-}
-
-static void set_spdifout(struct cm_state *s, unsigned rate)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	set_spdifout_unlocked(s,rate);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void set_spdifin_unlocked(struct cm_state *s, unsigned rate)
-{
-	if (rate == 48000 || rate == 44100) {
-		// SPDF_1
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
-		// SPDIFI48K SPDF_AC97
-		maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
-		s->status |= DO_SPDIF_IN;
-	} else {
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
-		s->status &= ~DO_SPDIF_IN;
-	}
-}
-
-static void set_spdifin(struct cm_state *s, unsigned rate)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	set_spdifin_unlocked(s,rate);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* find parity for bit 4~30 */
-static unsigned parity(unsigned data)
-{
-	unsigned parity = 0;
-	int counter = 4;
-
-	data >>= 4;	// start from bit 4
-	while (counter <= 30) {
-		if (data & 1)
-			parity++;
-		data >>= 1;
-		counter++;
-	}
-	return parity & 1;
-}
-
-static void set_ac3_unlocked(struct cm_state *s, unsigned rate)
-{
-	if (!(s->capability & CAN_AC3))
-		return;
-	/* enable AC3 */
-	if (rate && rate != 44100)
-		rate = 48000;
-	if (rate == 48000 || rate == 44100) {
-		// mute DAC
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, WSMUTE);
-		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0, MUTECH1);
-		// AC3EN for 039, 0x04
-		if (s->chip_version >= 39) {
-			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, AC3_EN);
-			if (s->chip_version == 55)
-				maskb(s->iobase + CODEC_CMI_SPDIF_CTRL, ~2, 0);
-		// AC3EN for 037, 0x10
-		} else if (s->chip_version == 37)
-			maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
-		if (s->capability & CAN_AC3_HW) {
-			// SPD24SEL for 039, 0x20, but cannot be set
-			if (s->chip_version == 39)
-				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, SPD24SEL);
-			// SPD24SEL for 037, 0x02
-			else if (s->chip_version == 37)
-				maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
-			if (s->chip_version >= 39)
-				maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, 0);
-
-			s->status |= DO_AC3_HW;
-		 } else {
-			// SPD32SEL for 037 & 039
-			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, SPD32SEL);
-			// set 176K sample rate to fix 033 HW bug
-			if (s->chip_version == 33) {
-				if (rate == 48000)
-					maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);
-				else
-					maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
-			}
-			s->status |= DO_AC3_SW;
-		}
-	} else {
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~WSMUTE, 0);
-		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~MUTECH1, 0);
-		maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~(SPD24SEL|0x12), 0);
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~(SPD32SEL|AC3_EN), 0);
-		if (s->chip_version == 33)
-			maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
-		if (s->chip_version >= 39)
-			maskb(s->iobase + CODEC_CMI_MIXER1, ~0, CDPLAY);
-		s->status &= ~DO_AC3;
-	}
-	s->spdif_counter = 0;
-}
-
-static void set_line_as_rear(struct cm_state *s, int use_line_as_rear)
-{
-	if (!(s->capability & CAN_LINE_AS_REAR))
-		return;
-	if (use_line_as_rear) {
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, SPK4);
-		s->status |= DO_LINE_AS_REAR;
-	} else {
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~SPK4, 0);
-		s->status &= ~DO_LINE_AS_REAR;
-	}
-}
-
-static void set_line_as_bass(struct cm_state *s, int use_line_as_bass)
-{
-	if (!(s->capability & CAN_LINE_AS_BASS))
-		return;
-	if (use_line_as_bass) {
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, CB2LIN);
-		s->status |= DO_LINE_AS_BASS;
-	} else {
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CB2LIN, 0);
-		s->status &= ~DO_LINE_AS_BASS;
-	}
-}
-
-static void set_mic_as_bass(struct cm_state *s, int use_mic_as_bass)
-{
-	if (!(s->capability & CAN_MIC_AS_BASS))
-		return;
-	if (use_mic_as_bass) {
-		maskb(s->iobase + CODEC_CMI_MISC, ~0, 0x04);
-		s->status |= DO_MIC_AS_BASS;
-	} else {
-		maskb(s->iobase + CODEC_CMI_MISC, ~0x04, 0);
-		s->status &= ~DO_MIC_AS_BASS;
-	}
-}
-
-static void set_hw_copy(struct cm_state *s, int hw_copy)
-{
-    	if (s->max_channels > 2 && hw_copy)
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, N4SPK3D);
-    	else
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~N4SPK3D, 0);
-}
-
-static void set_ac3(struct cm_state *s, unsigned rate)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	set_spdifout_unlocked(s, rate);
-	set_ac3_unlocked(s, rate);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int trans_ac3(struct cm_state *s, void *dest, const char __user *source, int size)
-{
-	int   i = size / 2;
-	unsigned long data;
-	unsigned short data16;
-	unsigned long *dst = (unsigned long *) dest;
-	unsigned short __user *src = (unsigned short __user *)source;
-	int err;
-
-	do {
-		if ((err = __get_user(data16, src++)))
-			return err;
-		data = (unsigned long)le16_to_cpu(data16);
-		data <<= 12;			// ok for 16-bit data
-		if (s->spdif_counter == 2 || s->spdif_counter == 3)
-			data |= 0x40000000;	// indicate AC-3 raw data
-		if (parity(data))
-			data |= 0x80000000;	// parity
-		if (s->spdif_counter == 0)
-			data |= 3;		// preamble 'M'
-		else if (s->spdif_counter & 1)
-			data |= 5;		// odd, 'W'
-		else
-			data |= 9;		// even, 'M'
-		*dst++ = cpu_to_le32(data);
-		s->spdif_counter++;
-		if (s->spdif_counter == 384)
-			s->spdif_counter = 0;
-	} while (--i);
-
-	return 0;
-}
-
-static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate)
-{
-	unsigned char freq = 4;
-	int	i;
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 8000)
-		rate = 8000;
-	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
-		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
-			rate = rate_lookup[i].rate;
-			freq = rate_lookup[i].freq;
-			break;
-	    	}
-	}
-	s->rateadc = rate;
-	freq <<= CM_FREQ_ADCSHIFT;
-
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
-}
-
-static void set_adc_rate(struct cm_state *s, unsigned rate)
-{
-	unsigned long flags;
-	unsigned char freq = 4;
-	int	i;
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 8000)
-		rate = 8000;
-	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
-		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
-			rate = rate_lookup[i].rate;
-			freq = rate_lookup[i].freq;
-			break;
-	    	}
-	}
-	s->rateadc = rate;
-	freq <<= CM_FREQ_ADCSHIFT;
-
-	spin_lock_irqsave(&s->lock, flags);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void set_dac_rate(struct cm_state *s, unsigned rate)
-{
-	unsigned long flags;
-	unsigned char freq = 4;
-	int	i;
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 8000)
-		rate = 8000;
-	for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
-		if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
-			rate = rate_lookup[i].rate;
-			freq = rate_lookup[i].freq;
-			break;
-	    	}
-	}
-	s->ratedac = rate;
-	freq <<= CM_FREQ_DACSHIFT;
-
-	spin_lock_irqsave(&s->lock, flags);
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~DSFC, freq);
-	spin_unlock_irqrestore(&s->lock, flags);
-
-	if (s->curr_channels <= 2 && spdif_out)
-		set_spdifout(s, rate);
-	if (s->status & DO_DUAL_DAC)
-		set_dac1_rate(s, rate);
-}
-
-/* --------------------------------------------------------------------- */
-static inline void reset_adc(struct cm_state *s)
-{
-	/* reset bus master */
-	outb(s->enable | RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	udelay(10);
-	outb(s->enable & ~RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-}
-
-static inline void reset_dac(struct cm_state *s)
-{
-	/* reset bus master */
-	outb(s->enable | RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	udelay(10);
-	outb(s->enable & ~RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	if (s->status & DO_DUAL_DAC)
-		reset_adc(s);
-}
-
-static inline void pause_adc(struct cm_state *s)
-{
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEADC);
-}
-
-static inline void pause_dac(struct cm_state *s)
-{
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEDAC);
-	if (s->status & DO_DUAL_DAC)
-		pause_adc(s);
-}
-
-static inline void disable_adc(struct cm_state *s)
-{
-	/* disable channel */
-	s->enable &= ~ENADC;
-	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	reset_adc(s);
-}
-
-static inline void disable_dac(struct cm_state *s)
-{
-	/* disable channel */
-	s->enable &= ~ENDAC;
-	outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	reset_dac(s);
-	if (s->status & DO_DUAL_DAC)
-		disable_adc(s);
-}
-
-static inline void enable_adc(struct cm_state *s)
-{
-	if (!(s->enable & ENADC)) {
-		/* enable channel */
-		s->enable |= ENADC;
-		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	}
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEADC, 0);
-}
-
-static inline void enable_dac_unlocked(struct cm_state *s)
-{
-	if (!(s->enable & ENDAC)) {
-		/* enable channel */
-		s->enable |= ENDAC;
-		outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-	}
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEDAC, 0);
-
-	if (s->status & DO_DUAL_DAC)
-		enable_adc(s);
-}
-
-static inline void stop_adc_unlocked(struct cm_state *s)
-{
-	if (s->enable & ENADC) {
-		/* disable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENADCINT, 0);
-		disable_adc(s);
-	}
-}
-
-static inline void stop_adc(struct cm_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	stop_adc_unlocked(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-
-}
-
-static inline void stop_dac_unlocked(struct cm_state *s)
-{
-	if (s->enable & ENDAC) {
-		/* disable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENDACINT, 0);
-		disable_dac(s);
-	}
-	if (s->status & DO_DUAL_DAC)
-		stop_dac1_unlocked(s);
-}
-
-static inline void stop_dac(struct cm_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	stop_dac_unlocked(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void start_adc_unlocked(struct cm_state *s)
-{
-	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
-	    && s->dma_adc.ready) {
-		/* enable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
-		enable_adc(s);
-	}
-}
-
-static void start_adc(struct cm_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	start_adc_unlocked(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac1_unlocked(struct cm_state *s)
-{
-	if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
-		/* enable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
- 		enable_dac_unlocked(s);
-	}
-}
-
-static void start_dac_unlocked(struct cm_state *s)
-{
-	if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
-		/* enable interrupt */
-		maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENDACINT);
-		enable_dac_unlocked(s);
-	}
-	if (s->status & DO_DUAL_DAC)
-		start_dac1_unlocked(s);
-}
-
-static void start_dac(struct cm_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	start_dac_unlocked(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int prog_dmabuf(struct cm_state *s, unsigned rec);
-
-static int set_dac_channels(struct cm_state *s, int channels)
-{
-	unsigned long flags;
-	static unsigned int fmmute = 0;
-
-	spin_lock_irqsave(&s->lock, flags);
-
-	if ((channels > 2) && (channels <= s->max_channels)
-	 && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {
-	    set_spdifout_unlocked(s, 0);
-	    if (s->capability & CAN_MULTI_CH_HW) {
-		// NXCHG
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, NXCHG);
-		// CHB3D or CHB3D5C
-	       	maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), channels > 4 ? CHB3D5C : CHB3D);
-		// CHB3D6C
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, channels == 6 ? CHB3D6C : 0);
-		// ENCENTER
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~ENCENTER, channels == 6 ? ENCENTER : 0);
-		s->status |= DO_MULTI_CH_HW;
-	    } else if (s->capability & CAN_DUAL_DAC) {
-		unsigned char fmtm = ~0, fmts = 0;
-		ssize_t ret;
-
-		// ENDBDAC, turn on double DAC mode
-		// XCHGDAC, CH0 -> back, CH1->front
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC);
-		// mute FM
-		fmmute = inb(s->iobase + CODEC_CMI_MIXER1) & FMMUTE;
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~0, FMMUTE);
-		s->status |= DO_DUAL_DAC;
-		// prepare secondary buffer
-		spin_unlock_irqrestore(&s->lock, flags);
-		ret = prog_dmabuf(s, 1);
-		if (ret) return ret;
-		spin_lock_irqsave(&s->lock, flags);
-
-		// copy the hw state
-		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
-		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
-		// the HW only support 16-bit stereo
-		fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
-		fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
-		fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
-		fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-
-		set_fmt_unlocked(s, fmtm, fmts);
-		set_adc_rate_unlocked(s, s->ratedac);
-	    }
-	    // disable 4 speaker mode (analog duplicate)
-	    set_hw_copy(s, 0);
-	    s->curr_channels = channels;
-
-	    // enable jack redirect
-	    set_line_as_rear(s, use_line_as_rear);
-	    if (channels > 4) {
-		    set_line_as_bass(s, use_line_as_bass);
-		    set_mic_as_bass(s, use_mic_as_bass);
-	    }
-	} else {
-	    if (s->status & DO_MULTI_CH_HW) {
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0);
-		maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), 0);
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0);
-	    } else if (s->status & DO_DUAL_DAC) {
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0);
-		maskb(s->iobase + CODEC_CMI_MIXER1, ~FMMUTE, fmmute);
-	    }
-	    // enable 4 speaker mode (analog duplicate)
-	    set_hw_copy(s, hw_copy);
-	    s->status &= ~DO_MULTI_CH;
-	    s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
-	    // disable jack redirect
-	    set_line_as_rear(s, hw_copy ? use_line_as_rear : 0);
-	    set_line_as_bass(s, 0);
-	    set_mic_as_bass(s, 0);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return s->curr_channels;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static void dealloc_dmabuf(struct cm_state *s, struct dmabuf *db)
-{
-	struct page *pstart, *pend;
-
-	if (db->rawbuf) {
-		/* undo marking the pages as reserved */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
-			ClearPageReserved(pstart);
-		pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
-	}
-	db->rawbuf = NULL;
-	db->mapped = db->ready = 0;
-}
-
-/* Ch1 is used for playback, Ch0 is used for recording */
-
-static int prog_dmabuf(struct cm_state *s, unsigned rec)
-{
-	struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
-	unsigned rate = rec ? s->rateadc : s->ratedac;
-	int order;
-	unsigned bytepersec;
-	unsigned bufs;
-	struct page *pstart, *pend;
-	unsigned char fmt;
-	unsigned long flags;
-
-	fmt = s->fmt;
-	if (rec) {
-		stop_adc(s);
-		fmt >>= CM_CFMT_ADCSHIFT;
-	} else {
-		stop_dac(s);
-		fmt >>= CM_CFMT_DACSHIFT;
-	}
-
-	fmt &= CM_CFMT_MASK;
-	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-			if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
-				break;
-		if (!db->rawbuf || !db->dmaaddr)
-			return -ENOMEM;
-		db->buforder = order;
-		/* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
-			SetPageReserved(pstart);
-	}
-	bytepersec = rate << sample_shift[fmt];
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytepersec)
-			db->fragshift = ld2(bytepersec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
- 	/* to make fragsize >= 4096 */
-	db->fragsamples = db->fragsize >> sample_shift[fmt];
-	db->dmasize = db->numfrag << db->fragshift;
-	db->dmasamples = db->dmasize >> sample_shift[fmt];
-	memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
-	spin_lock_irqsave(&s->lock, flags);
-	if (rec) {
-		if (s->status & DO_DUAL_DAC)
-		    set_dmadac1(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
-		else
-		    set_dmaadc(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
-		/* program sample counts */
-		set_countdac(s, db->fragsamples);
-	} else {
-		set_dmadac(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
-		/* program sample counts */
-		set_countdac(s, db->fragsamples);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	db->enabled = 1;
-	db->ready = 1;
-	return 0;
-}
-
-static inline void clear_advance(struct cm_state *s)
-{
-	unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;
-	unsigned char *buf = s->dma_dac.rawbuf;
-	unsigned char *buf1 = s->dma_adc.rawbuf;
-	unsigned bsize = s->dma_dac.dmasize;
-	unsigned bptr = s->dma_dac.swptr;
-	unsigned len = s->dma_dac.fragsize;
-
-	if (bptr + len > bsize) {
-		unsigned x = bsize - bptr;
-		memset(buf + bptr, c, x);
-		if (s->status & DO_DUAL_DAC)
-			memset(buf1 + bptr, c, x);
-		bptr = 0;
-		len -= x;
-	}
-	memset(buf + bptr, c, len);
-	if (s->status & DO_DUAL_DAC)
-		memset(buf1 + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void cm_update_ptr(struct cm_state *s)
-{
-	unsigned hwptr;
-	int diff;
-
-	/* update ADC pointer */
-	if (s->dma_adc.ready) {
-	    if (s->status & DO_DUAL_DAC) {
-		    /* the dac part will finish for this */
-	    } else {
-		hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
-		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
-		s->dma_adc.hwptr = hwptr;
-		s->dma_adc.total_bytes += diff;
-		s->dma_adc.count += diff;
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-			wake_up(&s->dma_adc.wait);
-		if (!s->dma_adc.mapped) {
-			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-				pause_adc(s);
-				s->dma_adc.error++;
-			}
-		}
-	    }
-	}
-	/* update DAC pointer */
-	if (s->dma_dac.ready) {
-		hwptr = get_dmadac(s) % s->dma_dac.dmasize;
-		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-		s->dma_dac.hwptr = hwptr;
-		s->dma_dac.total_bytes += diff;
-		if (s->status & DO_DUAL_DAC) {
-			s->dma_adc.hwptr = hwptr;
-			s->dma_adc.total_bytes += diff;
-		}
-		if (s->dma_dac.mapped) {
-			s->dma_dac.count += diff;
-			if (s->status & DO_DUAL_DAC)
-				s->dma_adc.count += diff;
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
-				wake_up(&s->dma_dac.wait);
-		} else {
-			s->dma_dac.count -= diff;
-			if (s->status & DO_DUAL_DAC)
-				s->dma_adc.count -= diff;
-			if (s->dma_dac.count <= 0) {
-				pause_dac(s);
-				s->dma_dac.error++;
-			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
-				clear_advance(s);
-				s->dma_dac.endcleared = 1;
-				if (s->status & DO_DUAL_DAC)
-					s->dma_adc.endcleared = 1;
-			}
-			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
-				wake_up(&s->dma_dac.wait);
-		}
-	}
-}
-
-static irqreturn_t cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct cm_state *s = (struct cm_state *)dev_id;
-	unsigned int intsrc, intstat;
-	unsigned char mask = 0;
-
-	/* fastpath out, to ease interrupt sharing */
-	intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
-	if (!(intsrc & 0x80000000))
-		return IRQ_NONE;
-	spin_lock(&s->lock);
-	intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-	/* acknowledge interrupt */
-	if (intsrc & ADCINT)
-		mask |= ENADCINT;
-	if (intsrc & DACINT)
-		mask |= ENDACINT;
-	outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-	outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
-	cm_update_ptr(s);
-	spin_unlock(&s->lock);
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-	if (intsrc & 0x00010000) {	// UART interrupt
-		if (s->midi_devc && intchk_mpu401((void *)s->midi_devc))
-			mpuintr(irq, (void *)s->midi_devc, regs);
-		else
-			inb(s->iomidi);// dummy read
-	}
-#endif
-	return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
-
-#define VALIDATE_STATE(s)                         \
-({                                                \
-	if (!(s) || (s)->magic != CM_MAGIC) { \
-		printk(invalid_magic);            \
-		return -ENXIO;                    \
-	}                                         \
-})
-
-/* --------------------------------------------------------------------- */
-
-#define MT_4          1
-#define MT_5MUTE      2
-#define MT_4MUTEMONO  3
-#define MT_6MUTE      4
-#define MT_5MUTEMONO  5
-
-static const struct {
-	unsigned left;
-	unsigned right;
-	unsigned type;
-	unsigned rec;
-	unsigned play;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
-	[SOUND_MIXER_CD]     = { DSP_MIX_CDVOLIDX_L,     DSP_MIX_CDVOLIDX_R,     MT_5MUTE,     0x04, 0x06 },
-	[SOUND_MIXER_LINE]   = { DSP_MIX_LINEVOLIDX_L,   DSP_MIX_LINEVOLIDX_R,   MT_5MUTE,     0x10, 0x18 },
-	[SOUND_MIXER_MIC]    = { DSP_MIX_MICVOLIDX,      DSP_MIX_MICVOLIDX,      MT_5MUTEMONO, 0x01, 0x01 },
-	[SOUND_MIXER_SYNTH]  = { DSP_MIX_FMVOLIDX_L,  	 DSP_MIX_FMVOLIDX_R,     MT_5MUTE,     0x40, 0x00 },
-	[SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE,     0x00, 0x00 },
-	[SOUND_MIXER_PCM]    = { DSP_MIX_VOICEVOLIDX_L,  DSP_MIX_VOICEVOLIDX_R,  MT_5MUTE,     0x00, 0x00 },
-	[SOUND_MIXER_LINE1]  = { DSP_MIX_AUXVOL_L,       DSP_MIX_AUXVOL_R,       MT_5MUTE,     0x80, 0x60 },
-	[SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX,	 DSP_MIX_SPKRVOLIDX,	 MT_5MUTEMONO, 0x00, 0x01 }
-};
-
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
-{
-	[SOUND_MIXER_CD]     = 1,
-	[SOUND_MIXER_LINE]   = 2,
-	[SOUND_MIXER_MIC]    = 3,
-	[SOUND_MIXER_SYNTH]  = 4,
-	[SOUND_MIXER_VOLUME] = 5,
-	[SOUND_MIXER_PCM]    = 6,
-	[SOUND_MIXER_LINE1]  = 7,
-	[SOUND_MIXER_SPEAKER]= 8
-};
-
-static unsigned mixer_outmask(struct cm_state *s)
-{
-	unsigned long flags;
-	int i, j, k;
-
-	spin_lock_irqsave(&s->lock, flags);
-	j = rdmixer(s, DSP_MIX_OUTMIXIDX);
-	spin_unlock_irqrestore(&s->lock, flags);
-	for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-		if (j & mixtable[i].play)
-			k |= 1 << i;
-	return k;
-}
-
-static unsigned mixer_recmask(struct cm_state *s)
-{
-	unsigned long flags;
-	int i, j, k;
-
-	spin_lock_irqsave(&s->lock, flags);
-	j = rdmixer(s, DSP_MIX_ADCMIXIDX_L);
-	spin_unlock_irqrestore(&s->lock, flags);
-	for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-		if (j & mixtable[i].rec)
-			k |= 1 << i;
-	return k;
-}
-
-static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
-{
-	unsigned long flags;
-	int i, val, j;
-	unsigned char l, r, rl, rr;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	VALIDATE_STATE(s);
-        if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, "cmpci", sizeof(info.id));
-		strlcpy(info.name, "C-Media PCI", sizeof(info.name));
-		info.modify_counter = s->mix.modcnt;
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, "cmpci", sizeof(info.id));
-		strlcpy(info.name, "C-Media cmpci", sizeof(info.name));
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, p);
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
-        if (_SIOC_DIR(cmd) == _SIOC_READ) {
-                switch (_IOC_NR(cmd)) {
-                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			val = mixer_recmask(s);
-			return put_user(val, p);
-
-                case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
-			val = mixer_outmask(s);
-			return put_user(val, p);
-
-                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].type)
-					val |= 1 << i;
-			return put_user(val, p);
-
-                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].rec)
-					val |= 1 << i;
-			return put_user(val, p);
-
-                case SOUND_MIXER_OUTMASK: /* Arg contains a bit for each supported recording source */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].play)
-					val |= 1 << i;
-			return put_user(val, p);
-
-                 case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
-					val |= 1 << i;
-			return put_user(val, p);
-
-                case SOUND_MIXER_CAPS:
-			return put_user(0, p);
-
-		default:
-			i = _IOC_NR(cmd);
-                        if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
-                                return -EINVAL;
-			if (!volidx[i])
-				return -EINVAL;
-			return put_user(s->mix.vol[volidx[i]-1], p);
-		}
-	}
-        if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
-		return -EINVAL;
-	s->mix.modcnt++;
-	switch (_IOC_NR(cmd)) {
-	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-		if (get_user(val, p))
-			return -EFAULT;
-		i = hweight32(val);
-		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			if (!(val & (1 << i)))
-				continue;
-			if (!mixtable[i].rec) {
-				val &= ~(1 << i);
-				continue;
-			}
-			j |= mixtable[i].rec;
-		}
-		spin_lock_irqsave(&s->lock, flags);
-		wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);
-		wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1) | (j & 0x80));
-		spin_unlock_irqrestore(&s->lock, flags);
-		return 0;
-
-	case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
-		if (get_user(val, p))
-			return -EFAULT;
-		for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			if (!(val & (1 << i)))
-				continue;
-			if (!mixtable[i].play) {
-				val &= ~(1 << i);
-				continue;
-			}
-			j |= mixtable[i].play;
-		}
-		spin_lock_irqsave(&s->lock, flags);
-		wrmixer(s, DSP_MIX_OUTMIXIDX, j);
-		spin_unlock_irqrestore(&s->lock, flags);
-		return 0;
-
-	default:
-		i = _IOC_NR(cmd);
-		if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
-			return -EINVAL;
-		if (get_user(val, p))
-			return -EFAULT;
-		l = val & 0xff;
-		r = (val >> 8) & 0xff;
-		if (l > 100)
-			l = 100;
-		if (r > 100)
-			r = 100;
-		spin_lock_irqsave(&s->lock, flags);
-		switch (mixtable[i].type) {
-		case MT_4:
-			if (l >= 10)
-				l -= 10;
-			if (r >= 10)
-				r -= 10;
-			frobindir(s, mixtable[i].left, 0xf0, l / 6);
-			frobindir(s, mixtable[i].right, 0xf0, l / 6);
-			break;
-
-		case MT_4MUTEMONO:
-			rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
-			rr = (rl >> 2) & 7;
-			wrmixer(s, mixtable[i].left, rl<<3);
-			if (i == SOUND_MIXER_MIC)
-				maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
-			break;
-
-		case MT_5MUTEMONO:
-			rl = l < 4 ? 0 : (l - 5) / 3;
- 			wrmixer(s, mixtable[i].left, rl<<3);
-			l = rdmixer(s, DSP_MIX_OUTMIXIDX) & ~mixtable[i].play;
-			r = rl ? mixtable[i].play : 0;
-			wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
-			/* for recording */
-			if (i == SOUND_MIXER_MIC) {
-				if (s->chip_version >= 37) {
-					rr = rl >> 1;
-					maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, (rr&0x07)<<1);
-					frobindir(s, DSP_MIX_EXTENSION, ~0x01, rr>>3);
-				} else {
-					rr = rl >> 2;
-					maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
-				}
-			}
-			break;
-
-		case MT_5MUTE:
-			rl = l < 4 ? 0 : (l - 5) / 3;
-			rr = r < 4 ? 0 : (r - 5) / 3;
- 			wrmixer(s, mixtable[i].left, rl<<3);
-			wrmixer(s, mixtable[i].right, rr<<3);
-			l = rdmixer(s, DSP_MIX_OUTMIXIDX);
-			l &= ~mixtable[i].play;
-			r = (rl|rr) ? mixtable[i].play : 0;
-			wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
-			break;
-
-		case MT_6MUTE:
-			if (l < 6)
-				rl = 0x00;
-			else
-				rl = l * 2 / 3;
-			if (r < 6)
-				rr = 0x00;
-			else
-				rr = r * 2 / 3;
-			wrmixer(s, mixtable[i].left, rl);
-			wrmixer(s, mixtable[i].right, rr);
-			break;
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		if (!volidx[i])
-			return -EINVAL;
-		s->mix.vol[volidx[i]-1] = val;
-		return put_user(s->mix.vol[volidx[i]-1], p);
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-static int cm_open_mixdev(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	struct list_head *list;
-	struct cm_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct cm_state, devs);
-		if (s->dev_mixer == minor)
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	return nonseekable_open(inode, file);
-}
-
-static int cm_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct cm_state *s = (struct cm_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	return 0;
-}
-
-static int cm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	return mixer_ioctl((struct cm_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations cm_mixer_fops = {
-	.owner	 = THIS_MODULE,
-	.llseek	 = no_llseek,
-	.ioctl	 = cm_ioctl_mixdev,
-	.open	 = cm_open_mixdev,
-	.release = cm_release_mixdev,
-};
-
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct cm_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count, tmo;
-
-	if (s->dma_dac.mapped || !s->dma_dac.ready)
-		return 0;
-        add_wait_queue(&s->dma_dac.wait, &wait);
-        for (;;) {
-        	__set_current_state(TASK_INTERRUPTIBLE);
-                spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-                spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-                        break;
-                if (nonblock) {
-                        remove_wait_queue(&s->dma_dac.wait, &wait);
-                        set_current_state(TASK_RUNNING);
-                        return -EBUSY;
-                }
-		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
-		tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
-		if (!schedule_timeout(tmo + 1))
-			DBG(printk(KERN_DEBUG "cmpci: dma timed out??\n");)
-        }
-        remove_wait_queue(&s->dma_dac.wait, &wait);
-        set_current_state(TASK_RUNNING);
-        if (signal_pending(current))
-                return -ERESTARTSYS;
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct cm_state *s = (struct cm_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_adc.mapped)
-		return -ENXIO;
-	if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-
-        add_wait_queue(&s->dma_adc.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		swptr = s->dma_adc.swptr;
-		cnt = s->dma_adc.dmasize-swptr;
-		if (s->dma_adc.count < cnt)
-			cnt = s->dma_adc.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (s->dma_adc.enabled)
-				start_adc(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				goto out;
-			}
-			if (!schedule_timeout(HZ)) {
-				printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
-				       s->dma_adc.hwptr, s->dma_adc.swptr);
-				spin_lock_irqsave(&s->lock, flags);
-				stop_adc_unlocked(s);
-				set_dmaadc(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
-				/* program sample counts */
-				set_countadc(s, s->dma_adc.fragsamples);
-				s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				goto out;
-			}
-			continue;
-		}
-		if (s->status & DO_BIGENDIAN_R) {
-			int	i, err;
-			unsigned char *src;
-			char __user *dst = buffer;
-			unsigned char data[2];
-
-			src = (unsigned char *) (s->dma_adc.rawbuf + swptr);
-			// copy left/right sample at one time
-			for (i = 0; i < cnt / 2; i++) {
-				data[0] = src[1];
-				data[1] = src[0];
-				if ((err = __put_user(data[0], dst++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __put_user(data[1], dst++))) {
-					ret = err;
-					goto out;
-				}
-				src += 2;
-			}
-		} else if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-		swptr = (swptr + cnt) % s->dma_adc.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_adc.swptr = swptr;
-		s->dma_adc.count -= cnt;
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_adc.enabled)
-			start_adc_unlocked(s);
-		spin_unlock_irqrestore(&s->lock, flags);
-	}
-out:
-        remove_wait_queue(&s->dma_adc.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static ssize_t cm_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct cm_state *s = (struct cm_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_dac.mapped)
-		return -ENXIO;
-	if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	if (s->status & DO_DUAL_DAC) {
-		if (s->dma_adc.mapped)
-			return -ENXIO;
-		if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
-			return ret;
-	}
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	ret = 0;
-
-        add_wait_queue(&s->dma_dac.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		if (s->dma_dac.count < 0) {
-			s->dma_dac.count = 0;
-			s->dma_dac.swptr = s->dma_dac.hwptr;
-		}
-		if (s->status & DO_DUAL_DAC) {
-			s->dma_adc.swptr = s->dma_dac.swptr;
-			s->dma_adc.count = s->dma_dac.count;
-			s->dma_adc.endcleared = s->dma_dac.endcleared;
-		}
-		swptr = s->dma_dac.swptr;
-		cnt = s->dma_dac.dmasize-swptr;
-		if (s->status & DO_AC3_SW) {
-			if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize)
-				cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2;
-		} else {
-			if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-				cnt = s->dma_dac.dmasize - s->dma_dac.count;
-		}
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if ((s->status & DO_DUAL_DAC) && (cnt > count / 2))
-		    cnt = count / 2;
-		if (cnt <= 0) {
-			if (s->dma_dac.enabled)
-				start_dac(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				goto out;
-			}
-			if (!schedule_timeout(HZ)) {
-				printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
-				       s->dma_dac.hwptr, s->dma_dac.swptr);
-				spin_lock_irqsave(&s->lock, flags);
-				stop_dac_unlocked(s);
-				set_dmadac(s, s->dma_dac.dmaaddr, s->dma_dac.dmasamples);
-				/* program sample counts */
-				set_countdac(s, s->dma_dac.fragsamples);
-				s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
-				if (s->status & DO_DUAL_DAC)  {
-					set_dmadac1(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
-					s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
-				}
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				goto out;
-			}
-			continue;
-		}
-		if (s->status & DO_AC3_SW) {
-			int err;
-
-			// clip exceeded data, caught by 033 and 037
-			if (swptr + 2 * cnt > s->dma_dac.dmasize)
-				cnt = (s->dma_dac.dmasize - swptr) / 2;
-			if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) {
-				ret = err;
-				goto out;
-			}
-			swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize;
-		} else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) {
-			int	i, err;
-			const char __user *src = buffer;
-			unsigned char *dst0, *dst1;
-			unsigned char data[8];
-
-			dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr);
-			dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr);
-			// copy left/right sample at one time
-			for (i = 0; i < cnt / 4; i++) {
-				if ((err = __get_user(data[0], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[1], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[2], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[3], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[4], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[5], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[6], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[7], src++))) {
-					ret = err;
-					goto out;
-				}
-				dst0[0] = data[1];
-				dst0[1] = data[0];
-				dst0[2] = data[3];
-				dst0[3] = data[2];
-				dst1[0] = data[5];
-				dst1[1] = data[4];
-				dst1[2] = data[7];
-				dst1[3] = data[6];
-				dst0 += 4;
-				dst1 += 4;
-			}
-			swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		} else if (s->status & DO_DUAL_DAC) {
-			int	i, err;
-			unsigned long __user *src = (unsigned long __user *) buffer;
-			unsigned long *dst0, *dst1;
-
-			dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr);
-			dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr);
-			// copy left/right sample at one time
-			for (i = 0; i < cnt / 4; i++) {
-				if ((err = __get_user(*dst0++, src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(*dst1++, src++))) {
-					ret = err;
-					goto out;
-				}
-			}
-			swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		} else if (s->status & DO_BIGENDIAN_W) {
-			int	i, err;
-			const char __user *src = buffer;
-			unsigned char *dst;
-			unsigned char data[2];
-
-			dst = (unsigned char *) (s->dma_dac.rawbuf + swptr);
-			// swap hi/lo bytes for each sample
-			for (i = 0; i < cnt / 2; i++) {
-				if ((err = __get_user(data[0], src++))) {
-					ret = err;
-					goto out;
-				}
-				if ((err = __get_user(data[1], src++))) {
-					ret = err;
-					goto out;
-				}
-				dst[0] = data[1];
-				dst[1] = data[0];
-				dst += 2;
-			}
-			swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		} else {
-			if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-				if (!ret)
-					ret = -EFAULT;
-				goto out;
-			}
-			swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		}
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_dac.swptr = swptr;
-		s->dma_dac.count += cnt;
-		if (s->status & DO_AC3_SW)
-			s->dma_dac.count += cnt;
-		s->dma_dac.endcleared = 0;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->status & DO_DUAL_DAC) {
-			count -= cnt;
-			buffer += cnt;
-			ret += cnt;
-		}
-		if (s->dma_dac.enabled)
-			start_dac(s);
-	}
-out:
-        remove_wait_queue(&s->dma_dac.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct cm_state *s = (struct cm_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready && prog_dmabuf(s, 0))
-			return 0;
-		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready && prog_dmabuf(s, 1))
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	cm_update_ptr(s);
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int cm_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct cm_state *s = (struct cm_state *)file->private_data;
-	struct dmabuf *db;
-	int ret = -EINVAL;
-	unsigned long size;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf(s, 0)) != 0)
-			goto out;
-		db = &s->dma_dac;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf(s, 1)) != 0)
-			goto out;
-		db = &s->dma_adc;
-	} else
-		goto out;
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder))
-		goto out;
-	ret = -EINVAL;
-	if (remap_pfn_range(vma, vma->vm_start,
-				virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
-				size, vma->vm_page_prot))
-		goto out;
-	db->mapped = 1;
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-#define SNDCTL_SPDIF_COPYRIGHT	_SIOW('S',  0, int)       // set/reset S/PDIF copy protection
-#define SNDCTL_SPDIF_LOOP	_SIOW('S',  1, int)       // set/reset S/PDIF loop
-#define SNDCTL_SPDIF_MONITOR	_SIOW('S',  2, int)       // set S/PDIF monitor
-#define SNDCTL_SPDIF_LEVEL	_SIOW('S',  3, int)       // set/reset S/PDIF out level
-#define SNDCTL_SPDIF_INV	_SIOW('S',  4, int)       // set/reset S/PDIF in inverse
-#define SNDCTL_SPDIF_SEL2	_SIOW('S',  5, int)       // set S/PDIF in #2
-#define SNDCTL_SPDIF_VALID	_SIOW('S',  6, int)       // set S/PDIF valid
-#define SNDCTL_SPDIFOUT		_SIOW('S',  7, int)       // set S/PDIF out
-#define SNDCTL_SPDIFIN		_SIOW('S',  8, int)       // set S/PDIF out
-
-static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct cm_state *s = (struct cm_state *)file->private_data;
-	unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
-	int val, mapped, ret;
-	unsigned char fmtm, fmtd;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	VALIDATE_STATE(s);
-        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, p);
-
-        case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq(s->irq);
-			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
-			if (s->status & DO_DUAL_DAC)
-				s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq(s->irq);
-			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SPEED:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-			if (file->f_mode & FMODE_READ) {
-			 	spin_lock_irqsave(&s->lock, flags);
-				stop_adc_unlocked(s);
-				s->dma_adc.ready = 0;
-				set_adc_rate_unlocked(s, val);
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (s->status & DO_DUAL_DAC)
-					s->dma_adc.ready = 0;
-				set_dac_rate(s, val);
-			}
-		}
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
-        case SNDCTL_DSP_STEREO:
-		if (get_user(val, p))
-			return -EFAULT;
-		fmtd = 0;
-		fmtm = ~0;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ready = 0;
-			if (val)
-				fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-			else
-				fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ready = 0;
-			if (val)
-				fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
-			else
-				fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
-			if (s->status & DO_DUAL_DAC) {
-				s->dma_adc.ready = 0;
-				if (val)
-					fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-				else
-					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
-			}
-		}
-		set_fmt(s, fmtm, fmtd);
-		return 0;
-
-        case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != 0) {
-			fmtd = 0;
-			fmtm = ~0;
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val >= 2)
-					fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-				else
-					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val >= 2)
-					fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
-				else
-					fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
-				if (s->status & DO_DUAL_DAC) {
-					s->dma_adc.ready = 0;
-					if (val >= 2)
-						fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-					else
-						fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
-				}
-			}
-			set_fmt(s, fmtm, fmtd);
-			if ((s->capability & CAN_MULTI_CH)
-			     && (file->f_mode & FMODE_WRITE)) {
-				val = set_dac_channels(s, val);
-				return put_user(val, p);
-			}
-		}
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT)
-					   : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
-
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8|
-			((s->capability & CAN_AC3) ? AFMT_AC3 : 0), p);
-
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			fmtd = 0;
-			fmtm = ~0;
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val == AFMT_S16_BE || val == AFMT_S16_LE)
-					fmtd |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
-				else
-					fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_ADCSHIFT);
-				if (val == AFMT_S16_BE)
-					s->status |= DO_BIGENDIAN_R;
-				else
-					s->status &= ~DO_BIGENDIAN_R;
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val == AFMT_S16_BE || val == AFMT_S16_LE || val == AFMT_AC3)
-					fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
-				else
-					fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
-				if (val == AFMT_AC3) {
-					fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
-					set_ac3(s, 48000);
-				} else
-					set_ac3(s, 0);
-				if (s->status & DO_DUAL_DAC) {
-					s->dma_adc.ready = 0;
-					if (val == AFMT_S16_BE || val == AFMT_S16_LE)
-						fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-					else
-						fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
-				}
-				if (val == AFMT_S16_BE)
-					s->status |= DO_BIGENDIAN_W;
-				else
-					s->status &= ~DO_BIGENDIAN_W;
-			}
-			set_fmt(s, fmtm, fmtd);
-		}
-		if (s->status & DO_AC3) return put_user(AFMT_AC3, p);
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
-					   : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, p);
-
-	case SNDCTL_DSP_POST:
-                return 0;
-
-        case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if (s->status & DO_DUAL_DAC) {
-			if (file->f_mode & FMODE_WRITE &&
-			 (s->enable & ENDAC) &&
-			 (s->enable & ENADC))
-				val |= PCM_ENABLE_OUTPUT;
-			return put_user(val, p);
-		}
-		if (file->f_mode & FMODE_READ && s->enable & ENADC)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && s->enable & ENDAC)
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, p);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
-					return ret;
-				s->dma_adc.enabled = 1;
-				start_adc(s);
-			} else {
-				s->dma_adc.enabled = 0;
-				stop_adc(s);
-			}
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-					return ret;
-				if (s->status & DO_DUAL_DAC) {
-					if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
-						return ret;
-				}
-				s->dma_dac.enabled = 1;
-				start_dac(s);
-			} else {
-				s->dma_dac.enabled = 0;
-				stop_dac(s);
-			}
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!(s->enable & ENDAC) && (val = prog_dmabuf(s, 0)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		cm_update_ptr(s);
-		abinfo.fragsize = s->dma_dac.fragsize;
-                abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
-                abinfo.fragstotal = s->dma_dac.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!(s->enable & ENADC) && (val = prog_dmabuf(s, 1)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		cm_update_ptr(s);
-		abinfo.fragsize = s->dma_adc.fragsize;
-                abinfo.bytes = s->dma_adc.count;
-                abinfo.fragstotal = s->dma_adc.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cm_update_ptr(s);
-                val = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, p);
-
-        case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cm_update_ptr(s);
-                cinfo.bytes = s->dma_adc.total_bytes;
-                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
-                cinfo.ptr = s->dma_adc.hwptr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= s->dma_adc.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-                return copy_to_user(argp, &cinfo, sizeof(cinfo))  ? -EFAULT : 0;
-
-        case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		spin_lock_irqsave(&s->lock, flags);
-		cm_update_ptr(s);
-                cinfo.bytes = s->dma_dac.total_bytes;
-                cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
-                cinfo.ptr = s->dma_dac.hwptr;
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= s->dma_dac.fragsize-1;
-		if (s->status & DO_DUAL_DAC) {
-			if (s->dma_adc.mapped)
-				s->dma_adc.count &= s->dma_adc.fragsize-1;
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-                return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-        case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf(s, 0)))
-				return val;
-			if (s->status & DO_DUAL_DAC) {
-				if ((val = prog_dmabuf(s, 1)))
-					return val;
-				return put_user(2 * s->dma_dac.fragsize, p);
-			}
-			return put_user(s->dma_dac.fragsize, p);
-		}
-		if ((val = prog_dmabuf(s, 1)))
-			return val;
-		return put_user(s->dma_adc.fragsize, p);
-
-        case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
-			if (s->status & DO_DUAL_DAC) {
-				s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
-				s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
-			}
-		}
-		return 0;
-
-        case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-			return -EINVAL;
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE) {
-			s->dma_dac.subdivision = val;
-			if (s->status & DO_DUAL_DAC)
-				s->dma_adc.subdivision = val;
-		}
-		return 0;
-
-        case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
-
-        case SOUND_PCM_READ_BITS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, p);
-
-        case SOUND_PCM_READ_FILTER:
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
-	case SNDCTL_DSP_GETCHANNELMASK:
-		return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, p);
-
-	case SNDCTL_DSP_BIND_CHANNEL:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val == DSP_BIND_QUERY) {
-			val = DSP_BIND_FRONT;
-			if (s->status & DO_SPDIF_OUT)
-				val |= DSP_BIND_SPDIF;
-			else {
-				if (s->curr_channels == 4)
-					val |= DSP_BIND_SURR;
-				if (s->curr_channels > 4)
-					val |= DSP_BIND_CENTER_LFE;
-			}
-		} else {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val & DSP_BIND_SPDIF) {
-					set_spdifin(s, s->rateadc);
-					if (!(s->status & DO_SPDIF_OUT))
-						val &= ~DSP_BIND_SPDIF;
-				}
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val & DSP_BIND_SPDIF) {
-					set_spdifout(s, s->ratedac);
-					set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
-					if (!(s->status & DO_SPDIF_OUT))
-						val &= ~DSP_BIND_SPDIF;
-				} else {
-					int channels;
-					int mask;
-
-					mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE);
-					switch (mask) {
-					    case DSP_BIND_FRONT:
-						channels = 2;
-						break;
-					    case DSP_BIND_FRONT|DSP_BIND_SURR:
-						channels = 4;
-						break;
-					    case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
-						channels = 6;
-						break;
-					    default:
-						channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
-						break;
-					}
-					set_dac_channels(s, channels);
-				}
-			}
-		}
-		return put_user(val, p);
-
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_MAPINBUF:
-	case SNDCTL_DSP_MAPOUTBUF:
-        case SNDCTL_DSP_SETSYNCRO:
-                return -EINVAL;
-	case SNDCTL_SPDIF_COPYRIGHT:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdif_copyright(s, val);
-                return 0;
-	case SNDCTL_SPDIF_LOOP:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdif_loop(s, val);
-                return 0;
-	case SNDCTL_SPDIF_MONITOR:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdif_monitor(s, val);
-                return 0;
-	case SNDCTL_SPDIF_LEVEL:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdifout_level(s, val);
-                return 0;
-	case SNDCTL_SPDIF_INV:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdifin_inverse(s, val);
-                return 0;
-	case SNDCTL_SPDIF_SEL2:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdifin_channel2(s, val);
-                return 0;
-	case SNDCTL_SPDIF_VALID:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdifin_valid(s, val);
-                return 0;
-	case SNDCTL_SPDIFOUT:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdifout(s, val ? s->ratedac : 0);
-                return 0;
-	case SNDCTL_SPDIFIN:
-		if (get_user(val, p))
-			return -EFAULT;
-		set_spdifin(s, val ? s->rateadc : 0);
-                return 0;
-	}
-	return mixer_ioctl(s, cmd, arg);
-}
-
-static int cm_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned char fmtm = ~0, fmts = 0;
-	struct list_head *list;
-	struct cm_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct cm_state, devs);
-		if (!((s->dev_audio ^ minor) & ~0xf))
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & file->f_mode) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	if (file->f_mode & FMODE_READ) {
-		s->status &= ~DO_BIGENDIAN_R;
-		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
-		s->dma_adc.enabled = 1;
-		set_adc_rate(s, 8000);
-		// spdif-in is turnned off by default
-		set_spdifin(s, 0);
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		s->status &= ~DO_BIGENDIAN_W;
-		fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
-		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
-		s->dma_dac.enabled = 1;
-		set_dac_rate(s, 8000);
-		// clear previous multichannel, spdif, ac3 state
-		set_spdifout(s, 0);
-		set_ac3(s, 0);
-		set_dac_channels(s, 1);
-	}
-	set_fmt(s, fmtm, fmts);
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int cm_release(struct inode *inode, struct file *file)
-{
-	struct cm_state *s = (struct cm_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE)
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac(s);
-
-		dealloc_dmabuf(s, &s->dma_dac);
-		if (s->status & DO_DUAL_DAC)
-			dealloc_dmabuf(s, &s->dma_adc);
-
-		if (s->status & DO_MULTI_CH)
-			set_dac_channels(s, 1);
-		if (s->status & DO_AC3)
-			set_ac3(s, 0);
-		if (s->status & DO_SPDIF_OUT)
-			set_spdifout(s, 0);
-		/* enable SPDIF loop */
-		set_spdif_loop(s, spdif_loop);
-		s->status &= ~DO_BIGENDIAN_W;
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-		dealloc_dmabuf(s, &s->dma_adc);
-		s->status &= ~DO_BIGENDIAN_R;
-	}
-	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
-	mutex_unlock(&s->open_mutex);
-	wake_up(&s->open_wait);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations cm_audio_fops = {
-	.owner	 = THIS_MODULE,
-	.llseek	 = no_llseek,
-	.read	 = cm_read,
-	.write	 = cm_write,
-	.poll	 = cm_poll,
-	.ioctl	 = cm_ioctl,
-	.mmap	 = cm_mmap,
-	.open	 = cm_open,
-	.release = cm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
-	int mixch;
-	int vol;
-} initvol[] __devinitdata = {
-	{ SOUND_MIXER_WRITE_CD, 0x4f4f },
-	{ SOUND_MIXER_WRITE_LINE, 0x4f4f },
-	{ SOUND_MIXER_WRITE_MIC, 0x4f4f },
-	{ SOUND_MIXER_WRITE_SYNTH, 0x4f4f },
-	{ SOUND_MIXER_WRITE_VOLUME, 0x4f4f },
-	{ SOUND_MIXER_WRITE_PCM, 0x4f4f }
-};
-
-/* check chip version and capability */
-static int query_chip(struct cm_state *s)
-{
-	int ChipVersion = -1;
-	unsigned char RegValue;
-
-	// check reg 0Ch, bit 24-31
-	RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3);
-	if (RegValue == 0) {
-	    // check reg 08h, bit 24-28
-	    RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3);
-	    RegValue &= 0x1f;
-	    if (RegValue == 0) {
-		ChipVersion = 33;
-		s->max_channels = 4;
-		s->capability |= CAN_AC3_SW;
-		s->capability |= CAN_DUAL_DAC;
-	    } else {
-		ChipVersion = 37;
-		s->max_channels = 4;
-		s->capability |= CAN_AC3_HW;
-		s->capability |= CAN_DUAL_DAC;
-	    }
-	} else {
-	    // check reg 0Ch, bit 26
-	    if (RegValue & (1 << (26-24))) {
-		ChipVersion = 39;
-	    	if (RegValue & (1 << (24-24)))
-		    s->max_channels = 6;
-	    	else
-		    s->max_channels = 4;
-		s->capability |= CAN_AC3_HW;
-		s->capability |= CAN_DUAL_DAC;
-		s->capability |= CAN_MULTI_CH_HW;
-		s->capability |= CAN_LINE_AS_BASS;
-		s->capability |= CAN_MIC_AS_BASS;
-	    } else {
-		ChipVersion = 55; // 4 or 6 channels
-		s->max_channels = 6;
-		s->capability |= CAN_AC3_HW;
-		s->capability |= CAN_DUAL_DAC;
-		s->capability |= CAN_MULTI_CH_HW;
-		s->capability |= CAN_LINE_AS_BASS;
-		s->capability |= CAN_MIC_AS_BASS;
-	    }
-	}
-	s->capability |= CAN_LINE_AS_REAR;
-	return ChipVersion;
-}
-
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-static int __devinit cm_create_gameport(struct cm_state *s, int io_port)
-{
-	struct gameport *gp;
-
-	if (!request_region(io_port, CM_EXTENT_GAME, "cmpci GAME")) {
-		printk(KERN_ERR "cmpci: gameport io ports 0x%#x in use\n", io_port);
-		return -EBUSY;
-	}
-
-	if (!(s->gameport = gp = gameport_allocate_port())) {
-		printk(KERN_ERR "cmpci: can not allocate memory for gameport\n");
-		release_region(io_port, CM_EXTENT_GAME);
-		return -ENOMEM;
-	}
-
-	gameport_set_name(gp, "C-Media GP");
-	gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
-	gp->dev.parent = &s->dev->dev;
-	gp->io = io_port;
-
-	/* enable joystick */
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
-
-	gameport_register_port(gp);
-
-	return 0;
-}
-
-static void __devexit cm_free_gameport(struct cm_state *s)
-{
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-
-		gameport_unregister_port(s->gameport);
-		s->gameport = NULL;
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
-		release_region(gpio, CM_EXTENT_GAME);
-	}
-}
-#else
-static inline int cm_create_gameport(struct cm_state *s, int io_port) { return -ENOSYS; }
-static inline void cm_free_gameport(struct cm_state *s) { }
-#endif
-
-#define	echo_option(x)\
-if (x) strcat(options, "" #x " ")
-
-static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
-	struct cm_state *s;
-	mm_segment_t fs;
-	int i, val, ret;
-	unsigned char reg_mask;
-	int timeout;
-	struct resource *ports;
-	struct {
-		unsigned short	deviceid;
-		char		*devicename;
-	} devicetable[] = {
-		{ PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" },
-		{ PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" },
-		{ PCI_DEVICE_ID_CMEDIA_CM8738,  "CM8738" },
-		{ PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
-	};
-	char	*devicename = "unknown";
-	char	options[256];
-
-	if ((ret = pci_enable_device(pcidev)))
-		return ret;
-	if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO))
-		return -ENODEV;
-	if (pcidev->irq == 0)
-		return -ENODEV;
-	i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
-	if (i) {
-		printk(KERN_WARNING "cmpci: architecture does not support 32bit PCI busmaster DMA\n");
-		return i;
-	}
-	s = kmalloc(sizeof(*s), GFP_KERNEL);
-	if (!s) {
-		printk(KERN_WARNING "cmpci: out of memory\n");
-		return -ENOMEM;
-	}
-	/* search device name */
-	for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
-		if (devicetable[i].deviceid == pcidev->device) {
-			devicename = devicetable[i].devicename;
-			break;
-		}
-	}
-	memset(s, 0, sizeof(struct cm_state));
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac.wait);
-	init_waitqueue_head(&s->open_wait);
-	mutex_init(&s->open_mutex);
-	spin_lock_init(&s->lock);
-	s->magic = CM_MAGIC;
-	s->dev = pcidev;
-	s->iobase = pci_resource_start(pcidev, 0);
-	s->iosynth = fmio;
-	s->iomidi = mpuio;
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-	s->midi_devc = 0;
-#endif
-	s->status = 0;
-	if (s->iobase == 0)
-		return -ENODEV;
-	s->irq = pcidev->irq;
-
-	if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
-		printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
-		ret = -EBUSY;
-		goto err_region5;
-	}
-	/* dump parameters */
-	strcpy(options, "cmpci: ");
-	echo_option(joystick);
-	echo_option(spdif_inverse);
-	echo_option(spdif_loop);
-	echo_option(spdif_out);
-	echo_option(use_line_as_rear);
-	echo_option(use_line_as_bass);
-	echo_option(use_mic_as_bass);
-	echo_option(mic_boost);
-	echo_option(hw_copy);
-	printk(KERN_INFO "%s\n", options);
-
-	/* initialize codec registers */
-	outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
-	outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
-	/* reset mixer */
-	wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
-	/* request irq */
-	if ((ret = request_irq(s->irq, cm_interrupt, IRQF_SHARED, "cmpci", s))) {
-		printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
-		goto err_irq;
-	}
-	printk(KERN_INFO "cmpci: found %s adapter at io %#x irq %u\n",
-	       devicename, s->iobase, s->irq);
-	/* register devices */
-	if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) {
-		ret = s->dev_audio;
-		goto err_dev1;
-	}
-	if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0) {
-		ret = s->dev_mixer;
-		goto err_dev2;
-	}
-	pci_set_master(pcidev);	/* enable bus mastering */
-	/* initialize the chips */
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	/* set mixer output */
-	frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f);
-	/* set mixer input */
-	val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD|SOUND_MASK_MIC;
-	mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
-	for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
-		val = initvol[i].vol;
-		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
-	}
-	set_fs(fs);
-	/* use channel 1 for playback, channel 0 for record */
-	maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, CHADC0);
-	/* turn off VMIC3 - mic boost */
-	if (mic_boost)
-		maskb(s->iobase + CODEC_CMI_MIXER2, ~1, 0);
-	else
-		maskb(s->iobase + CODEC_CMI_MIXER2, ~0, 1);
-	s->deviceid = pcidev->device;
-
-	if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738
-	 || pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738B) {
-
-		/* chip version and hw capability check */
-		s->chip_version = query_chip(s);
-		printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version);
-
-		/* set SPDIF-in inverse before enable SPDIF loop */
-		set_spdifin_inverse(s, spdif_inverse);
-
-		/* use SPDIF in #1 */
-		set_spdifin_channel2(s, 0);
-	} else {
-		s->chip_version = 0;
-		/* 8338 will fall here */
-		s->max_channels = 4;
-		s->capability |= CAN_DUAL_DAC;
-		s->capability |= CAN_LINE_AS_REAR;
-	}
-	/* enable SPDIF loop */
-	set_spdif_loop(s, spdif_loop);
-
-	// enable 4 speaker mode (analog duplicate)
-	set_hw_copy(s, hw_copy);
-
-	reg_mask = 0;
-#ifdef CONFIG_SOUND_CMPCI_FM
-	/* disable FM */
-	maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
-	if (s->iosynth) {
-	    /* don't enable OPL3 if there is one */
-	    if (opl3_detect(s->iosynth, NULL)) {
-	    	s->iosynth = 0;
-	    } else {
-		/* set IO based at 0x388 */
-		switch (s->iosynth) {
-		    case 0x388:
-			reg_mask = 0;
-			break;
-		    case 0x3C8:
-			reg_mask = 0x01;
-			break;
-		    case 0x3E0:
-			reg_mask = 0x02;
-			break;
-		    case 0x3E8:
-			reg_mask = 0x03;
-			break;
-		    default:
-			s->iosynth = 0;
-			break;
-		}
-		maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
-		/* enable FM */
-		if (s->iosynth) {
-			maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
-			if (opl3_detect(s->iosynth, NULL))
-				ret = opl3_init(s->iosynth, NULL, THIS_MODULE);
-			else {
-				maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
-				s->iosynth = 0;
-			}
-		}
-	    }
-	}
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-	switch (s->iomidi) {
-	    case 0x330:
-		reg_mask = 0;
-		break;
-	    case 0x320:
-		reg_mask = 0x20;
-		break;
-	    case 0x310:
-		reg_mask = 0x40;
-		break;
-	    case 0x300:
-		reg_mask = 0x60;
-		break;
-	    default:
-		s->iomidi = 0;
-		goto skip_mpu;
-	}
-	ports = request_region(s->iomidi, 2, "mpu401");
-	if (!ports)
-		goto skip_mpu;
-	/* disable MPU-401 */
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
-	s->mpu_data.name = "cmpci mpu";
-	s->mpu_data.io_base = s->iomidi;
-	s->mpu_data.irq = -s->irq;	// tell mpu401 to share irq
-	if (probe_mpu401(&s->mpu_data, ports)) {
-		release_region(s->iomidi, 2);
-		s->iomidi = 0;
-		goto skip_mpu;
-	}
-	maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x60, reg_mask);
-	/* enable MPU-401 */
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
-	/* clear all previously received interrupt */
-	for (timeout = 900000; timeout > 0; timeout--) {
-		if ((inb(s->iomidi + 1) && 0x80) == 0)
-			inb(s->iomidi);
-		else
-			break;
-	}
-	if (!probe_mpu401(&s->mpu_data, ports)) {
-		release_region(s->iomidi, 2);
-		s->iomidi = 0;
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
-	} else {
-		attach_mpu401(&s->mpu_data, THIS_MODULE);
-		s->midi_devc = s->mpu_data.slots[1];
-	}
-skip_mpu:
-#endif
-	/* disable joystick port */
-	maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
-	if (joystick)
-		cm_create_gameport(s, 0x200);
-
-	/* store it in the driver field */
-	pci_set_drvdata(pcidev, s);
-	/* put it into driver list */
-	list_add_tail(&s->devs, &devs);
-	/* increment devindex */
-	if (devindex < NR_DEVICE-1)
-		devindex++;
-	return 0;
-
-err_dev2:
-	unregister_sound_dsp(s->dev_audio);
-err_dev1:
-	printk(KERN_ERR "cmpci: cannot register misc device\n");
-	free_irq(s->irq, s);
-err_irq:
-	release_region(s->iobase, CM_EXTENT_CODEC);
-err_region5:
-	kfree(s);
-	return ret;
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw");
-MODULE_DESCRIPTION("CM8x38 Audio Driver");
-MODULE_LICENSE("GPL");
-
-static void __devexit cm_remove(struct pci_dev *dev)
-{
-	struct cm_state *s = pci_get_drvdata(dev);
-
-	if (!s)
-		return;
-
-	cm_free_gameport(s);
-
-#ifdef CONFIG_SOUND_CMPCI_FM
-	if (s->iosynth) {
-		/* disable FM */
-		maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
-	}
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-	if (s->iomidi) {
-		unload_mpu401(&s->mpu_data);
-		/* disable MPU-401 */
-		maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
-	}
-#endif
-	set_spdif_loop(s, 0);
-	list_del(&s->devs);
-	outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2);  /* disable ints */
-	synchronize_irq(s->irq);
-	outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
-	free_irq(s->irq, s);
-
-	/* reset mixer */
-	wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
-	release_region(s->iobase, CM_EXTENT_CODEC);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->dev_mixer);
-	kfree(s);
-	pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] __devinitdata = {
-	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- 	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-	{ PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver cm_driver = {
-       .name	 = "cmpci",
-       .id_table = id_table,
-       .probe	 = cm_probe,
-       .remove	 = __devexit_p(cm_remove)
-};
-
-static int __init init_cmpci(void)
-{
-	printk(KERN_INFO "cmpci: version $Revision: 6.82 $ time " __TIME__ " " __DATE__ "\n");
-	return pci_register_driver(&cm_driver);
-}
-
-static void __exit cleanup_cmpci(void)
-{
-	printk(KERN_INFO "cmpci: unloading\n");
-	pci_unregister_driver(&cm_driver);
-}
-
-module_init(init_cmpci);
-module_exit(cleanup_cmpci);
diff --git a/sound/oss/cs4281/Makefile b/sound/oss/cs4281/Makefile
deleted file mode 100644
index 6d527e8..0000000
--- a/sound/oss/cs4281/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# Makefile for Cirrus Logic-Crystal CS4281 
-#
-
-obj-$(CONFIG_SOUND_CS4281) += cs4281.o
-
-cs4281-objs += cs4281m.o
diff --git a/sound/oss/cs4281/cs4281_hwdefs.h b/sound/oss/cs4281/cs4281_hwdefs.h
deleted file mode 100644
index 701d595..0000000
--- a/sound/oss/cs4281/cs4281_hwdefs.h
+++ /dev/null
@@ -1,1234 +0,0 @@
-//****************************************************************************
-//
-// HWDEFS.H - Definitions of the registers and data structures used by the
-//            CS4281
-//
-// Copyright (c) 1999,2000,2001 Crystal Semiconductor Corp.
-//
-//****************************************************************************
-
-#ifndef _H_HWDEFS
-#define _H_HWDEFS
-
-//****************************************************************************
-//
-// The following define the offsets of the registers located in the PCI
-// configuration space of the CS4281 part.
-//
-//****************************************************************************
-#define PCICONFIG_DEVID_VENID                   0x00000000L
-#define PCICONFIG_STATUS_COMMAND                0x00000004L
-#define PCICONFIG_CLASS_REVISION                0x00000008L
-#define PCICONFIG_LATENCY_TIMER                 0x0000000CL
-#define PCICONFIG_BA0                           0x00000010L
-#define PCICONFIG_BA1                           0x00000014L
-#define PCICONFIG_SUBSYSID_SUBSYSVENID          0x0000002CL
-#define PCICONFIG_INTERRUPT                     0x0000003CL
-
-//****************************************************************************
-//
-// The following define the offsets of the registers accessed via base address
-// register zero on the CS4281 part.
-//
-//****************************************************************************
-#define BA0_HISR                                0x00000000L
-#define BA0_HICR                                0x00000008L
-#define BA0_HIMR                                0x0000000CL
-#define BA0_IIER                                0x00000010L
-#define BA0_HDSR0                               0x000000F0L
-#define BA0_HDSR1                               0x000000F4L
-#define BA0_HDSR2                               0x000000F8L
-#define BA0_HDSR3                               0x000000FCL
-#define BA0_DCA0                                0x00000110L
-#define BA0_DCC0                                0x00000114L
-#define BA0_DBA0                                0x00000118L
-#define BA0_DBC0                                0x0000011CL
-#define BA0_DCA1                                0x00000120L
-#define BA0_DCC1                                0x00000124L
-#define BA0_DBA1                                0x00000128L
-#define BA0_DBC1                                0x0000012CL
-#define BA0_DCA2                                0x00000130L
-#define BA0_DCC2                                0x00000134L
-#define BA0_DBA2                                0x00000138L
-#define BA0_DBC2                                0x0000013CL
-#define BA0_DCA3                                0x00000140L
-#define BA0_DCC3                                0x00000144L
-#define BA0_DBA3                                0x00000148L
-#define BA0_DBC3                                0x0000014CL
-#define BA0_DMR0                                0x00000150L
-#define BA0_DCR0                                0x00000154L
-#define BA0_DMR1                                0x00000158L
-#define BA0_DCR1                                0x0000015CL
-#define BA0_DMR2                                0x00000160L
-#define BA0_DCR2                                0x00000164L
-#define BA0_DMR3                                0x00000168L
-#define BA0_DCR3                                0x0000016CL
-#define BA0_DLMR                                0x00000170L
-#define BA0_DLSR                                0x00000174L
-#define BA0_FCR0                                0x00000180L
-#define BA0_FCR1                                0x00000184L
-#define BA0_FCR2                                0x00000188L
-#define BA0_FCR3                                0x0000018CL
-#define BA0_FPDR0                               0x00000190L
-#define BA0_FPDR1                               0x00000194L
-#define BA0_FPDR2                               0x00000198L
-#define BA0_FPDR3                               0x0000019CL
-#define BA0_FCHS                                0x0000020CL
-#define BA0_FSIC0                               0x00000210L
-#define BA0_FSIC1                               0x00000214L
-#define BA0_FSIC2                               0x00000218L
-#define BA0_FSIC3                               0x0000021CL
-#define BA0_PCICFG00                            0x00000300L
-#define BA0_PCICFG04                            0x00000304L
-#define BA0_PCICFG08                            0x00000308L
-#define BA0_PCICFG0C                            0x0000030CL
-#define BA0_PCICFG10                            0x00000310L
-#define BA0_PCICFG14                            0x00000314L
-#define BA0_PCICFG18                            0x00000318L
-#define BA0_PCICFG1C                            0x0000031CL
-#define BA0_PCICFG20                            0x00000320L
-#define BA0_PCICFG24                            0x00000324L
-#define BA0_PCICFG28                            0x00000328L
-#define BA0_PCICFG2C                            0x0000032CL
-#define BA0_PCICFG30                            0x00000330L
-#define BA0_PCICFG34                            0x00000334L
-#define BA0_PCICFG38                            0x00000338L
-#define BA0_PCICFG3C                            0x0000033CL
-#define BA0_PCICFG40                            0x00000340L
-#define BA0_PMCS                                0x00000344L
-#define BA0_CWPR                                0x000003E0L
-#define BA0_EPPMC                               0x000003E4L
-#define BA0_GPIOR                               0x000003E8L
-#define BA0_SPMC                                0x000003ECL
-#define BA0_CFLR                                0x000003F0L
-#define BA0_IISR                                0x000003F4L
-#define BA0_TMS                                 0x000003F8L
-#define BA0_SSVID                               0x000003FCL
-#define BA0_CLKCR1                              0x00000400L
-#define BA0_FRR                                 0x00000410L
-#define BA0_SLT12O                              0x0000041CL
-#define BA0_SERMC                               0x00000420L
-#define BA0_SERC1                               0x00000428L
-#define BA0_SERC2                               0x0000042CL
-#define BA0_SLT12M                              0x0000045CL
-#define BA0_ACCTL                               0x00000460L
-#define BA0_ACSTS                               0x00000464L
-#define BA0_ACOSV                               0x00000468L
-#define BA0_ACCAD                               0x0000046CL
-#define BA0_ACCDA                               0x00000470L
-#define BA0_ACISV                               0x00000474L
-#define BA0_ACSAD                               0x00000478L
-#define BA0_ACSDA                               0x0000047CL
-#define BA0_JSPT                                0x00000480L
-#define BA0_JSCTL                               0x00000484L
-#define BA0_MIDCR                               0x00000490L
-#define BA0_MIDCMD                              0x00000494L
-#define BA0_MIDSR                               0x00000494L
-#define BA0_MIDWP                               0x00000498L
-#define BA0_MIDRP                               0x0000049CL
-#define BA0_AODSD1                              0x000004A8L
-#define BA0_AODSD2                              0x000004ACL
-#define BA0_CFGI                                0x000004B0L
-#define BA0_SLT12M2                             0x000004DCL
-#define BA0_ACSTS2                              0x000004E4L
-#define BA0_ACISV2                              0x000004F4L
-#define BA0_ACSAD2                              0x000004F8L
-#define BA0_ACSDA2                              0x000004FCL
-#define BA0_IOTGP                               0x00000500L
-#define BA0_IOTSB                               0x00000504L
-#define BA0_IOTFM                               0x00000508L
-#define BA0_IOTDMA                              0x0000050CL
-#define BA0_IOTAC0                              0x00000500L
-#define BA0_IOTAC1                              0x00000504L
-#define BA0_IOTAC2                              0x00000508L
-#define BA0_IOTAC3                              0x0000050CL
-#define BA0_IOTPCP                              0x0000052CL
-#define BA0_IOTCC                               0x00000530L
-#define BA0_IOTCR                               0x0000058CL
-#define BA0_PCPRR                               0x00000600L
-#define BA0_PCPGR                               0x00000604L
-#define BA0_PCPCR                               0x00000608L
-#define BA0_PCPCIEN                             0x00000608L
-#define BA0_SBMAR                               0x00000700L
-#define BA0_SBMDR                               0x00000704L
-#define BA0_SBRR                                0x00000708L
-#define BA0_SBRDP                               0x0000070CL
-#define BA0_SBWDP                               0x00000710L
-#define BA0_SBWBS                               0x00000710L
-#define BA0_SBRBS                               0x00000714L
-#define BA0_FMSR                                0x00000730L
-#define BA0_B0AP                                0x00000730L
-#define BA0_FMDP                                0x00000734L
-#define BA0_B1AP                                0x00000738L
-#define BA0_B1DP                                0x0000073CL
-#define BA0_SSPM                                0x00000740L
-#define BA0_DACSR                               0x00000744L
-#define BA0_ADCSR                               0x00000748L
-#define BA0_SSCR                                0x0000074CL
-#define BA0_FMLVC                               0x00000754L
-#define BA0_FMRVC                               0x00000758L
-#define BA0_SRCSA                               0x0000075CL
-#define BA0_PPLVC                               0x00000760L
-#define BA0_PPRVC                               0x00000764L
-#define BA0_PASR                                0x00000768L
-#define BA0_CASR                                0x0000076CL
-
-//****************************************************************************
-//
-// The following define the offsets of the AC97 shadow registers, which appear
-// as a virtual extension to the base address register zero memory range.
-//
-//****************************************************************************
-#define AC97_REG_OFFSET_MASK                    0x0000007EL
-#define AC97_CODEC_NUMBER_MASK                  0x00003000L
-
-#define BA0_AC97_RESET                          0x00001000L
-#define BA0_AC97_MASTER_VOLUME                  0x00001002L
-#define BA0_AC97_HEADPHONE_VOLUME               0x00001004L
-#define BA0_AC97_MASTER_VOLUME_MONO             0x00001006L
-#define BA0_AC97_MASTER_TONE                    0x00001008L
-#define BA0_AC97_PC_BEEP_VOLUME                 0x0000100AL
-#define BA0_AC97_PHONE_VOLUME                   0x0000100CL
-#define BA0_AC97_MIC_VOLUME                     0x0000100EL
-#define BA0_AC97_LINE_IN_VOLUME                 0x00001010L
-#define BA0_AC97_CD_VOLUME                      0x00001012L
-#define BA0_AC97_VIDEO_VOLUME                   0x00001014L
-#define BA0_AC97_AUX_VOLUME                     0x00001016L
-#define BA0_AC97_PCM_OUT_VOLUME                 0x00001018L
-#define BA0_AC97_RECORD_SELECT                  0x0000101AL
-#define BA0_AC97_RECORD_GAIN                    0x0000101CL
-#define BA0_AC97_RECORD_GAIN_MIC                0x0000101EL
-#define BA0_AC97_GENERAL_PURPOSE                0x00001020L
-#define BA0_AC97_3D_CONTROL                     0x00001022L
-#define BA0_AC97_MODEM_RATE                     0x00001024L
-#define BA0_AC97_POWERDOWN                      0x00001026L
-#define BA0_AC97_EXT_AUDIO_ID                   0x00001028L
-#define BA0_AC97_EXT_AUDIO_POWER                0x0000102AL
-#define BA0_AC97_PCM_FRONT_DAC_RATE             0x0000102CL
-#define BA0_AC97_PCM_SURR_DAC_RATE              0x0000102EL
-#define BA0_AC97_PCM_LFE_DAC_RATE               0x00001030L
-#define BA0_AC97_PCM_LR_ADC_RATE                0x00001032L
-#define BA0_AC97_MIC_ADC_RATE                   0x00001034L
-#define BA0_AC97_6CH_VOL_C_LFE                  0x00001036L
-#define BA0_AC97_6CH_VOL_SURROUND               0x00001038L
-#define BA0_AC97_RESERVED_3A                    0x0000103AL
-#define BA0_AC97_EXT_MODEM_ID                   0x0000103CL
-#define BA0_AC97_EXT_MODEM_POWER                0x0000103EL
-#define BA0_AC97_LINE1_CODEC_RATE               0x00001040L
-#define BA0_AC97_LINE2_CODEC_RATE               0x00001042L
-#define BA0_AC97_HANDSET_CODEC_RATE             0x00001044L
-#define BA0_AC97_LINE1_CODEC_LEVEL              0x00001046L
-#define BA0_AC97_LINE2_CODEC_LEVEL              0x00001048L
-#define BA0_AC97_HANDSET_CODEC_LEVEL            0x0000104AL
-#define BA0_AC97_GPIO_PIN_CONFIG                0x0000104CL
-#define BA0_AC97_GPIO_PIN_TYPE                  0x0000104EL
-#define BA0_AC97_GPIO_PIN_STICKY                0x00001050L
-#define BA0_AC97_GPIO_PIN_WAKEUP                0x00001052L
-#define BA0_AC97_GPIO_PIN_STATUS                0x00001054L
-#define BA0_AC97_MISC_MODEM_AFE_STAT            0x00001056L
-#define BA0_AC97_RESERVED_58                    0x00001058L
-#define BA0_AC97_CRYSTAL_REV_N_FAB_ID           0x0000105AL
-#define BA0_AC97_TEST_AND_MISC_CTRL             0x0000105CL
-#define BA0_AC97_AC_MODE                        0x0000105EL
-#define BA0_AC97_MISC_CRYSTAL_CONTROL           0x00001060L
-#define BA0_AC97_LINE1_HYPRID_CTRL              0x00001062L
-#define BA0_AC97_VENDOR_RESERVED_64             0x00001064L
-#define BA0_AC97_VENDOR_RESERVED_66             0x00001066L
-#define BA0_AC97_SPDIF_CONTROL                  0x00001068L
-#define BA0_AC97_VENDOR_RESERVED_6A             0x0000106AL
-#define BA0_AC97_VENDOR_RESERVED_6C             0x0000106CL
-#define BA0_AC97_VENDOR_RESERVED_6E             0x0000106EL
-#define BA0_AC97_VENDOR_RESERVED_70             0x00001070L
-#define BA0_AC97_VENDOR_RESERVED_72             0x00001072L
-#define BA0_AC97_VENDOR_RESERVED_74             0x00001074L
-#define BA0_AC97_CAL_ADDRESS                    0x00001076L
-#define BA0_AC97_CAL_DATA                       0x00001078L
-#define BA0_AC97_VENDOR_RESERVED_7A             0x0000107AL
-#define BA0_AC97_VENDOR_ID1                     0x0000107CL
-#define BA0_AC97_VENDOR_ID2                     0x0000107EL
-
-//****************************************************************************
-//
-// The following define the offsets of the registers and memories accessed via
-// base address register one on the CS4281 part.
-//
-//****************************************************************************
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI device ID/vendor ID
-// register.
-//
-//****************************************************************************
-#define PDV_VENID_MASK                          0x0000FFFFL
-#define PDV_DEVID_MASK                          0xFFFF0000L
-#define PDV_VENID_SHIFT                         0L
-#define PDV_DEVID_SHIFT                         16L
-#define VENID_CIRRUS_LOGIC                      0x1013L
-#define DEVID_CS4281                            0x6005L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI status and command
-// register.
-//
-//****************************************************************************
-#define PSC_IO_SPACE_ENABLE                     0x00000001L
-#define PSC_MEMORY_SPACE_ENABLE                 0x00000002L
-#define PSC_BUS_MASTER_ENABLE                   0x00000004L
-#define PSC_SPECIAL_CYCLES                      0x00000008L
-#define PSC_MWI_ENABLE                          0x00000010L
-#define PSC_VGA_PALETTE_SNOOP                   0x00000020L
-#define PSC_PARITY_RESPONSE                     0x00000040L
-#define PSC_WAIT_CONTROL                        0x00000080L
-#define PSC_SERR_ENABLE                         0x00000100L
-#define PSC_FAST_B2B_ENABLE                     0x00000200L
-#define PSC_UDF_MASK                            0x007F0000L
-#define PSC_FAST_B2B_CAPABLE                    0x00800000L
-#define PSC_PARITY_ERROR_DETECTED               0x01000000L
-#define PSC_DEVSEL_TIMING_MASK                  0x06000000L
-#define PSC_TARGET_ABORT_SIGNALLED              0x08000000L
-#define PSC_RECEIVED_TARGET_ABORT               0x10000000L
-#define PSC_RECEIVED_MASTER_ABORT               0x20000000L
-#define PSC_SIGNALLED_SERR                      0x40000000L
-#define PSC_DETECTED_PARITY_ERROR               0x80000000L
-#define PSC_UDF_SHIFT                           16L
-#define PSC_DEVSEL_TIMING_SHIFT                 25L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI class/revision ID
-// register.
-//
-//****************************************************************************
-#define PCR_REVID_MASK                          0x000000FFL
-#define PCR_INTERFACE_MASK                      0x0000FF00L
-#define PCR_SUBCLASS_MASK                       0x00FF0000L
-#define PCR_CLASS_MASK                          0xFF000000L
-#define PCR_REVID_SHIFT                         0L
-#define PCR_INTERFACE_SHIFT                     8L
-#define PCR_SUBCLASS_SHIFT                      16L
-#define PCR_CLASS_SHIFT                         24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI latency timer register.
-//
-//****************************************************************************
-#define PLT_CACHE_LINE_SIZE_MASK                0x000000FFL
-#define PLT_LATENCY_TIMER_MASK                  0x0000FF00L
-#define PLT_HEADER_TYPE_MASK                    0x00FF0000L
-#define PLT_BIST_MASK                           0xFF000000L
-#define PLT_CACHE_LINE_SIZE_SHIFT               0L
-#define PLT_LATENCY_TIMER_SHIFT                 8L
-#define PLT_HEADER_TYPE_SHIFT                   16L
-#define PLT_BIST_SHIFT                          24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI base address registers.
-//
-//****************************************************************************
-#define PBAR_MEMORY_SPACE_INDICATOR             0x00000001L
-#define PBAR_LOCATION_TYPE_MASK                 0x00000006L
-#define PBAR_NOT_PREFETCHABLE                   0x00000008L
-#define PBAR_ADDRESS_MASK                       0xFFFFFFF0L
-#define PBAR_LOCATION_TYPE_SHIFT                1L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI subsystem ID/subsystem
-// vendor ID register.
-//
-//****************************************************************************
-#define PSS_SUBSYSTEM_VENDOR_ID_MASK            0x0000FFFFL
-#define PSS_SUBSYSTEM_ID_MASK                   0xFFFF0000L
-#define PSS_SUBSYSTEM_VENDOR_ID_SHIFT           0L
-#define PSS_SUBSYSTEM_ID_SHIFT                  16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI interrupt register.
-//
-//****************************************************************************
-#define PI_LINE_MASK                            0x000000FFL
-#define PI_PIN_MASK                             0x0000FF00L
-#define PI_MIN_GRANT_MASK                       0x00FF0000L
-#define PI_MAX_LATENCY_MASK                     0xFF000000L
-#define PI_LINE_SHIFT                           0L
-#define PI_PIN_SHIFT                            8L
-#define PI_MIN_GRANT_SHIFT                      16L
-#define PI_MAX_LATENCY_SHIFT                    24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the host interrupt status
-// register.
-//
-//****************************************************************************
-#define HISR_HVOLMASK                            0x00000003L
-#define HISR_VDNI                                0x00000001L
-#define HISR_VUPI                                0x00000002L
-#define HISR_GP1I                                0x00000004L
-#define HISR_GP3I                                0x00000008L
-#define HISR_GPSI                                0x00000010L
-#define HISR_GPPI                                0x00000020L
-#define HISR_DMAI                                0x00040000L
-#define HISR_FIFOI                               0x00100000L
-#define HISR_HVOL                                0x00200000L
-#define HISR_MIDI                                0x00400000L
-#define HISR_SBINT                               0x00800000L
-#define HISR_INTENA                              0x80000000L
-#define HISR_DMA_MASK                            0x00000F00L
-#define HISR_FIFO_MASK                           0x0000F000L
-#define HISR_DMA_SHIFT                           8L
-#define HISR_FIFO_SHIFT                          12L
-#define HISR_FIFO0                               0x00001000L
-#define HISR_FIFO1                               0x00002000L
-#define HISR_FIFO2                               0x00004000L
-#define HISR_FIFO3                               0x00008000L
-#define HISR_DMA0                                0x00000100L
-#define HISR_DMA1                                0x00000200L
-#define HISR_DMA2                                0x00000400L
-#define HISR_DMA3                                0x00000800L
-#define HISR_RESERVED                            0x40000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the host interrupt control
-// register.
-//
-//****************************************************************************
-#define HICR_IEV                                 0x00000001L
-#define HICR_CHGM                                0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the DMA Mode Register n
-// (DMRn)
-//
-//****************************************************************************
-#define DMRn_TR_MASK                             0x0000000CL
-#define DMRn_TR_SHIFT                            2L
-#define DMRn_AUTO                                0x00000010L
-#define DMRn_TR_READ                             0x00000008L
-#define DMRn_TR_WRITE                            0x00000004L
-#define DMRn_TYPE_MASK                           0x000000C0L
-#define DMRn_TYPE_SHIFT                          6L
-#define DMRn_SIZE8                               0x00010000L
-#define DMRn_MONO                                0x00020000L
-#define DMRn_BEND                                0x00040000L
-#define DMRn_USIGN                               0x00080000L
-#define DMRn_SIZE20                              0x00100000L
-#define DMRn_SWAPC                               0x00400000L
-#define DMRn_CBC                                 0x01000000L
-#define DMRn_TBC                                 0x02000000L
-#define DMRn_POLL                                0x10000000L
-#define DMRn_DMA                                 0x20000000L
-#define DMRn_FSEL_MASK                           0xC0000000L
-#define DMRn_FSEL_SHIFT                          30L
-#define DMRn_FSEL0                               0x00000000L
-#define DMRn_FSEL1                               0x40000000L
-#define DMRn_FSEL2                               0x80000000L
-#define DMRn_FSEL3                               0xC0000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the DMA Command Register n
-// (DCRn)
-//
-//****************************************************************************
-#define DCRn_HTCIE                               0x00020000L
-#define DCRn_TCIE                                0x00010000L
-#define DCRn_MSK                                 0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the FIFO Control 
-// register n.(FCRn)
-//
-//****************************************************************************
-#define FCRn_OF_MASK                            0x0000007FL
-#define FCRn_OF_SHIFT                           0L
-#define FCRn_SZ_MASK                            0x00007F00L
-#define FCRn_SZ_SHIFT                           8L
-#define FCRn_LS_MASK                            0x001F0000L
-#define FCRn_LS_SHIFT                           16L
-#define FCRn_RS_MASK                            0x1F000000L
-#define FCRn_RS_SHIFT                           24L
-#define FCRn_FEN                                0x80000000L
-#define FCRn_PSH                                0x20000000L
-#define FCRn_DACZ                               0x40000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port Power Management
-// control register.(SPMC)
-//
-//****************************************************************************
-#define SPMC_RSTN                               0x00000001L
-#define SPMC_ASYN                               0x00000002L
-#define SPMC_WUP1                               0x00000004L
-#define SPMC_WUP2                               0x00000008L
-#define SPMC_ASDI2E                             0x00000100L
-#define SPMC_ESSPD                              0x00000200L
-#define SPMC_GISPEN                             0x00004000L
-#define SPMC_GIPPEN                             0x00008000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Configuration Load register.
-// (CFLR)
-//
-//****************************************************************************
-#define CFLR_CLOCK_SOURCE_MASK                  0x00000003L
-#define CFLR_CLOCK_SOURCE_AC97                  0x00000001L
-
-#define CFLR_CB0_MASK                            0x000000FFL
-#define CFLR_CB1_MASK                            0x0000FF00L
-#define CFLR_CB2_MASK                            0x00FF0000L
-#define CFLR_CB3_MASK                            0xFF000000L
-#define CFLR_CB0_SHIFT                           0L
-#define CFLR_CB1_SHIFT                           8L
-#define CFLR_CB2_SHIFT                           16L
-#define CFLR_CB3_SHIFT                           24L
-
-#define IOTCR_DMA0                              0x00000000L
-#define IOTCR_DMA1                              0x00000400L
-#define IOTCR_DMA2                              0x00000800L
-#define IOTCR_DMA3                              0x00000C00L
-#define IOTCR_CCLS                              0x00000100L
-#define IOTCR_PCPCI                             0x00000200L
-#define IOTCR_DDMA                              0x00000300L
-
-#define SBWBS_WBB                               0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the SRC Slot Assignment Register
-// (SRCSA)
-//
-//****************************************************************************
-#define SRCSA_PLSS_MASK                         0x0000001FL
-#define SRCSA_PLSS_SHIFT                        0L
-#define SRCSA_PRSS_MASK                         0x00001F00L
-#define SRCSA_PRSS_SHIFT                        8L
-#define SRCSA_CLSS_MASK                         0x001F0000L
-#define SRCSA_CLSS_SHIFT                        16L
-#define SRCSA_CRSS_MASK                         0x1F000000L
-#define SRCSA_CRSS_SHIFT                        24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound System Power Management
-// register.(SSPM)
-//
-//****************************************************************************
-#define SSPM_FPDN                               0x00000080L
-#define SSPM_MIXEN                              0x00000040L
-#define SSPM_CSRCEN                             0x00000020L
-#define SSPM_PSRCEN                             0x00000010L
-#define SSPM_JSEN                               0x00000008L
-#define SSPM_ACLEN                              0x00000004L
-#define SSPM_FMEN                               0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound System Control
-// Register. (SSCR)
-//
-//****************************************************************************
-#define SSCR_SB                                 0x00000004L
-#define SSCR_HVC                                0x00000008L
-#define SSCR_LPFIFO                             0x00000040L
-#define SSCR_LPSRC                              0x00000080L
-#define SSCR_XLPSRC                             0x00000100L
-#define SSCR_MVMD                               0x00010000L
-#define SSCR_MVAD                               0x00020000L
-#define SSCR_MVLD                               0x00040000L
-#define SSCR_MVCS                               0x00080000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Clock Control Register 1. 
-// (CLKCR1)
-//
-//****************************************************************************
-#define CLKCR1_DLLSS_MASK                       0x0000000CL
-#define CLKCR1_DLLSS_SHIFT                      2L
-#define CLKCR1_DLLP                             0x00000010L
-#define CLKCR1_SWCE                             0x00000020L
-#define CLKCR1_DLLOS                            0x00000040L
-#define CLKCR1_CKRA                             0x00010000L
-#define CLKCR1_CKRN                             0x00020000L
-#define CLKCR1_DLLRDY                           0x01000000L
-#define CLKCR1_CLKON                            0x02000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound Blaster Read Buffer
-// Status.(SBRBS)
-//
-//****************************************************************************
-#define SBRBS_RD_MASK                           0x0000007FL
-#define SBRBS_RD_SHIFT                          0L
-#define SBRBS_RBF                               0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port master control
-// register.(SERMC)
-//
-//****************************************************************************
-#define SERMC_MSPE                              0x00000001L
-#define SERMC_PTC_MASK                          0x0000000EL
-#define SERMC_PTC_SHIFT                         1L
-#define SERMC_PTC_AC97                          0x00000002L
-#define SERMC_PLB                               0x00000010L
-#define SERMC_PXLB                              0x00000020L
-#define SERMC_LOFV                              0x00080000L
-#define SERMC_SLB                               0x00100000L
-#define SERMC_SXLB                              0x00200000L
-#define SERMC_ODSEN1                            0x01000000L
-#define SERMC_ODSEN2                            0x02000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the General Purpose I/O Register. 
-// (GPIOR)
-//
-//****************************************************************************
-#define GPIOR_VDNS                              0x00000001L
-#define GPIOR_VUPS                              0x00000002L
-#define GPIOR_GP1S                              0x00000004L
-#define GPIOR_GP3S                              0x00000008L
-#define GPIOR_GPSS                              0x00000010L
-#define GPIOR_GPPS                              0x00000020L
-#define GPIOR_GP1D                              0x00000400L
-#define GPIOR_GP3D                              0x00000800L
-#define GPIOR_VDNLT                             0x00010000L
-#define GPIOR_VDNPO                             0x00020000L
-#define GPIOR_VDNST                             0x00040000L
-#define GPIOR_VDNW                              0x00080000L
-#define GPIOR_VUPLT                             0x00100000L
-#define GPIOR_VUPPO                             0x00200000L
-#define GPIOR_VUPST                             0x00400000L
-#define GPIOR_VUPW                              0x00800000L
-#define GPIOR_GP1OE                             0x01000000L
-#define GPIOR_GP1PT                             0x02000000L
-#define GPIOR_GP1ST                             0x04000000L
-#define GPIOR_GP1W                              0x08000000L
-#define GPIOR_GP3OE                             0x10000000L
-#define GPIOR_GP3PT                             0x20000000L
-#define GPIOR_GP3ST                             0x40000000L
-#define GPIOR_GP3W                              0x80000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the clock control register 1.
-//
-//****************************************************************************
-#define CLKCR1_PLLSS_MASK                       0x0000000CL
-#define CLKCR1_PLLSS_SERIAL                     0x00000000L
-#define CLKCR1_PLLSS_CRYSTAL                    0x00000004L
-#define CLKCR1_PLLSS_PCI                        0x00000008L
-#define CLKCR1_PLLSS_RESERVED                   0x0000000CL
-#define CLKCR1_PLLP                             0x00000010L
-#define CLKCR1_SWCE                             0x00000020L
-#define CLKCR1_PLLOS                            0x00000040L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the feature reporting register.
-//
-//****************************************************************************
-#define FRR_FAB_MASK                            0x00000003L
-#define FRR_MASK_MASK                           0x0000001CL
-#define FRR_ID_MASK                             0x00003000L
-#define FRR_FAB_SHIFT                           0L
-#define FRR_MASK_SHIFT                          2L
-#define FRR_ID_SHIFT                            12L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port 1 configuration
-// register.
-//
-//****************************************************************************
-#define SERC1_VALUE                             0x00000003L
-#define SERC1_SO1EN                             0x00000001L
-#define SERC1_SO1F_MASK                         0x0000000EL
-#define SERC1_SO1F_CS423X                       0x00000000L
-#define SERC1_SO1F_AC97                         0x00000002L
-#define SERC1_SO1F_DAC                          0x00000004L
-#define SERC1_SO1F_SPDIF                        0x00000006L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port 2 configuration
-// register.
-//
-//****************************************************************************
-#define SERC2_VALUE                             0x00000003L
-#define SERC2_SI1EN                             0x00000001L
-#define SERC2_SI1F_MASK                         0x0000000EL
-#define SERC2_SI1F_CS423X                       0x00000000L
-#define SERC2_SI1F_AC97                         0x00000002L
-#define SERC2_SI1F_ADC                          0x00000004L
-#define SERC2_SI1F_SPDIF                        0x00000006L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 control register.
-//
-//****************************************************************************
-#define ACCTL_ESYN                              0x00000002L
-#define ACCTL_VFRM                              0x00000004L
-#define ACCTL_DCV                               0x00000008L
-#define ACCTL_CRW                               0x00000010L
-#define ACCTL_TC                                0x00000040L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status register.
-//
-//****************************************************************************
-#define ACSTS_CRDY                              0x00000001L
-#define ACSTS_VSTS                              0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 output slot valid
-// register.
-//
-//****************************************************************************
-#define ACOSV_SLV3                              0x00000001L
-#define ACOSV_SLV4                              0x00000002L
-#define ACOSV_SLV5                              0x00000004L
-#define ACOSV_SLV6                              0x00000008L
-#define ACOSV_SLV7                              0x00000010L
-#define ACOSV_SLV8                              0x00000020L
-#define ACOSV_SLV9                              0x00000040L
-#define ACOSV_SLV10                             0x00000080L
-#define ACOSV_SLV11                             0x00000100L
-#define ACOSV_SLV12                             0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 command address
-// register.
-//
-//****************************************************************************
-#define ACCAD_CI_MASK                           0x0000007FL
-#define ACCAD_CI_SHIFT                          0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 command data register.
-//
-//****************************************************************************
-#define ACCDA_CD_MASK                           0x0000FFFFL
-#define ACCDA_CD_SHIFT                          0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 input slot valid
-// register.
-//
-//****************************************************************************
-#define ACISV_ISV3                              0x00000001L
-#define ACISV_ISV4                              0x00000002L
-#define ACISV_ISV5                              0x00000004L
-#define ACISV_ISV6                              0x00000008L
-#define ACISV_ISV7                              0x00000010L
-#define ACISV_ISV8                              0x00000020L
-#define ACISV_ISV9                              0x00000040L
-#define ACISV_ISV10                             0x00000080L
-#define ACISV_ISV11                             0x00000100L
-#define ACISV_ISV12                             0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status address
-// register.
-//
-//****************************************************************************
-#define ACSAD_SI_MASK                           0x0000007FL
-#define ACSAD_SI_SHIFT                          0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status data register.
-//
-//****************************************************************************
-#define ACSDA_SD_MASK                           0x0000FFFFL
-#define ACSDA_SD_SHIFT                          0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers (all 12).
-//
-//****************************************************************************
-#define IOTAC_SA_MASK                           0x0000FFFFL
-#define IOTAC_MSK_MASK                          0x000F0000L
-#define IOTAC_IODC_MASK                         0x06000000L
-#define IOTAC_IODC_16_BIT                       0x00000000L
-#define IOTAC_IODC_10_BIT                       0x02000000L
-#define IOTAC_IODC_12_BIT                       0x04000000L
-#define IOTAC_WSPI                              0x08000000L
-#define IOTAC_RSPI                              0x10000000L
-#define IOTAC_WSE                               0x20000000L
-#define IOTAC_WE                                0x40000000L
-#define IOTAC_RE                                0x80000000L
-#define IOTAC_SA_SHIFT                          0L
-#define IOTAC_MSK_SHIFT                         16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI master enable
-// register.
-//
-//****************************************************************************
-#define PCPCIEN_EN                              0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the joystick poll/trigger
-// register.
-//
-//****************************************************************************
-#define JSPT_CAX                                0x00000001L
-#define JSPT_CAY                                0x00000002L
-#define JSPT_CBX                                0x00000004L
-#define JSPT_CBY                                0x00000008L
-#define JSPT_BA1                                0x00000010L
-#define JSPT_BA2                                0x00000020L
-#define JSPT_BB1                                0x00000040L
-#define JSPT_BB2                                0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the joystick control register.
-// The TBF bit has been moved from MIDSR register to JSCTL register bit 8.
-//
-//****************************************************************************
-#define JSCTL_SP_MASK                           0x00000003L
-#define JSCTL_SP_SLOW                           0x00000000L
-#define JSCTL_SP_MEDIUM_SLOW                    0x00000001L
-#define JSCTL_SP_MEDIUM_FAST                    0x00000002L
-#define JSCTL_SP_FAST                           0x00000003L
-#define JSCTL_ARE                               0x00000004L
-#define JSCTL_TBF                               0x00000100L
-
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI control register.
-//
-//****************************************************************************
-#define MIDCR_TXE                               0x00000001L
-#define MIDCR_RXE                               0x00000002L
-#define MIDCR_RIE                               0x00000004L
-#define MIDCR_TIE                               0x00000008L
-#define MIDCR_MLB                               0x00000010L
-#define MIDCR_MRST                              0x00000020L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI status register.
-//
-//****************************************************************************
-#define MIDSR_RBE                               0x00000080L
-#define MIDSR_RDA                               0x00008000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI write port register.
-//
-//****************************************************************************
-#define MIDWP_MWD_MASK                          0x000000FFL
-#define MIDWP_MWD_SHIFT                         0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI read port register.
-//
-//****************************************************************************
-#define MIDRP_MRD_MASK                          0x000000FFL
-#define MIDRP_MRD_SHIFT                         0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the configuration interface
-// register.
-//
-//****************************************************************************
-#define CFGI_CLK                                0x00000001L
-#define CFGI_DOUT                               0x00000002L
-#define CFGI_DIN_EEN                            0x00000004L
-#define CFGI_EELD                               0x00000008L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the subsystem ID and vendor ID
-// register.
-//
-//****************************************************************************
-#define SSVID_VID_MASK                          0x0000FFFFL
-#define SSVID_SID_MASK                          0xFFFF0000L
-#define SSVID_VID_SHIFT                         0L
-#define SSVID_SID_SHIFT                         16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the GPIO pin interface register.
-//
-//****************************************************************************
-#define GPIOR_VOLDN                             0x00000001L
-#define GPIOR_VOLUP                             0x00000002L
-#define GPIOR_SI2D                              0x00000004L
-#define GPIOR_SI2OE                             0x00000008L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status register 2.
-//
-//****************************************************************************
-#define ACSTS2_CRDY                             0x00000001L
-#define ACSTS2_VSTS                             0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 input slot valid
-// register 2.
-//
-//****************************************************************************
-#define ACISV2_ISV3                             0x00000001L
-#define ACISV2_ISV4                             0x00000002L
-#define ACISV2_ISV5                             0x00000004L
-#define ACISV2_ISV6                             0x00000008L
-#define ACISV2_ISV7                             0x00000010L
-#define ACISV2_ISV8                             0x00000020L
-#define ACISV2_ISV9                             0x00000040L
-#define ACISV2_ISV10                            0x00000080L
-#define ACISV2_ISV11                            0x00000100L
-#define ACISV2_ISV12                            0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status address
-// register 2.
-//
-//****************************************************************************
-#define ACSAD2_SI_MASK                          0x0000007FL
-#define ACSAD2_SI_SHIFT                         0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status data register 2.
-//
-//****************************************************************************
-#define ACSDA2_SD_MASK                          0x0000FFFFL
-#define ACSDA2_SD_SHIFT                         0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap control register.
-//
-//****************************************************************************
-#define IOTCR_ITD                               0x00000001L
-#define IOTCR_HRV                               0x00000002L
-#define IOTCR_SRV                               0x00000004L
-#define IOTCR_DTI                               0x00000008L
-#define IOTCR_DFI                               0x00000010L
-#define IOTCR_DDP                               0x00000020L
-#define IOTCR_JTE                               0x00000040L
-#define IOTCR_PPE                               0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for Hardware Master Volume.  
-//
-//****************************************************************************
-#define IOTGP_SA_MASK                           0x0000FFFFL
-#define IOTGP_MSK_MASK                          0x000F0000L
-#define IOTGP_IODC_MASK                         0x06000000L
-#define IOTGP_IODC_16_BIT                       0x00000000L
-#define IOTGP_IODC_10_BIT                       0x02000000L
-#define IOTGP_IODC_12_BIT                       0x04000000L
-#define IOTGP_WSPI                              0x08000000L
-#define IOTGP_RSPI                              0x10000000L
-#define IOTGP_WSE                               0x20000000L
-#define IOTGP_WE                                0x40000000L
-#define IOTGP_RE                                0x80000000L
-#define IOTGP_SA_SHIFT                          0L
-#define IOTGP_MSK_SHIFT                         16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for Sound Blaster
-//
-//****************************************************************************
-#define IOTSB_SA_MASK                           0x0000FFFFL
-#define IOTSB_MSK_MASK                          0x000F0000L
-#define IOTSB_IODC_MASK                         0x06000000L
-#define IOTSB_IODC_16_BIT                       0x00000000L
-#define IOTSB_IODC_10_BIT                       0x02000000L
-#define IOTSB_IODC_12_BIT                       0x04000000L
-#define IOTSB_WSPI                              0x08000000L
-#define IOTSB_RSPI                              0x10000000L
-#define IOTSB_WSE                               0x20000000L
-#define IOTSB_WE                                0x40000000L
-#define IOTSB_RE                                0x80000000L
-#define IOTSB_SA_SHIFT                          0L
-#define IOTSB_MSK_SHIFT                         16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for FM.
-//
-//****************************************************************************
-#define IOTFM_SA_MASK                           0x0000FFFFL
-#define IOTFM_MSK_MASK                          0x000F0000L
-#define IOTFM_IODC_MASK                         0x06000000L
-#define IOTFM_IODC_16_BIT                       0x00000000L
-#define IOTFM_IODC_10_BIT                       0x02000000L
-#define IOTFM_IODC_12_BIT                       0x04000000L
-#define IOTFM_WSPI                              0x08000000L
-#define IOTFM_RSPI                              0x10000000L
-#define IOTFM_WSE                               0x20000000L
-#define IOTFM_WE                                0x40000000L
-#define IOTFM_RE                                0x80000000L
-#define IOTFM_SA_SHIFT                          0L
-#define IOTFM_MSK_SHIFT                         16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI request register.
-//
-//****************************************************************************
-#define PCPRR_RDC_MASK                         0x00000007L
-#define PCPRR_REQ                              0x00008000L
-#define PCPRR_RDC_SHIFT                        0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI grant register.
-//
-//****************************************************************************
-#define PCPGR_GDC_MASK                         0x00000007L
-#define PCPGR_VL                               0x00008000L
-#define PCPGR_GDC_SHIFT                        0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI Control Register.
-//
-//****************************************************************************
-#define PCPCR_EN                               0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the debug index register.
-//
-//****************************************************************************
-#define DREG_REGID_MASK                         0x0000007FL
-#define DREG_DEBUG                              0x00000080L
-#define DREG_RGBK_MASK                          0x00000700L
-#define DREG_TRAP                               0x00000800L
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_TRAPX                              0x00001000L
-#endif
-#endif
-#define DREG_REGID_SHIFT                        0L
-#define DREG_RGBK_SHIFT                         8L
-#define DREG_RGBK_REGID_MASK                    0x0000077FL
-#define DREG_REGID_R0                           0x00000010L
-#define DREG_REGID_R1                           0x00000011L
-#define DREG_REGID_R2                           0x00000012L
-#define DREG_REGID_R3                           0x00000013L
-#define DREG_REGID_R4                           0x00000014L
-#define DREG_REGID_R5                           0x00000015L
-#define DREG_REGID_R6                           0x00000016L
-#define DREG_REGID_R7                           0x00000017L
-#define DREG_REGID_R8                           0x00000018L
-#define DREG_REGID_R9                           0x00000019L
-#define DREG_REGID_RA                           0x0000001AL
-#define DREG_REGID_RB                           0x0000001BL
-#define DREG_REGID_RC                           0x0000001CL
-#define DREG_REGID_RD                           0x0000001DL
-#define DREG_REGID_RE                           0x0000001EL
-#define DREG_REGID_RF                           0x0000001FL
-#define DREG_REGID_RA_BUS_LOW                   0x00000020L
-#define DREG_REGID_RA_BUS_HIGH                  0x00000038L
-#define DREG_REGID_YBUS_LOW                     0x00000050L
-#define DREG_REGID_YBUS_HIGH                    0x00000058L
-#define DREG_REGID_TRAP_0                       0x00000100L
-#define DREG_REGID_TRAP_1                       0x00000101L
-#define DREG_REGID_TRAP_2                       0x00000102L
-#define DREG_REGID_TRAP_3                       0x00000103L
-#define DREG_REGID_TRAP_4                       0x00000104L
-#define DREG_REGID_TRAP_5                       0x00000105L
-#define DREG_REGID_TRAP_6                       0x00000106L
-#define DREG_REGID_TRAP_7                       0x00000107L
-#define DREG_REGID_INDIRECT_ADDRESS             0x0000010EL
-#define DREG_REGID_TOP_OF_STACK                 0x0000010FL
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_8                       0x00000110L
-#define DREG_REGID_TRAP_9                       0x00000111L
-#define DREG_REGID_TRAP_10                      0x00000112L
-#define DREG_REGID_TRAP_11                      0x00000113L
-#define DREG_REGID_TRAP_12                      0x00000114L
-#define DREG_REGID_TRAP_13                      0x00000115L
-#define DREG_REGID_TRAP_14                      0x00000116L
-#define DREG_REGID_TRAP_15                      0x00000117L
-#define DREG_REGID_TRAP_16                      0x00000118L
-#define DREG_REGID_TRAP_17                      0x00000119L
-#define DREG_REGID_TRAP_18                      0x0000011AL
-#define DREG_REGID_TRAP_19                      0x0000011BL
-#define DREG_REGID_TRAP_20                      0x0000011CL
-#define DREG_REGID_TRAP_21                      0x0000011DL
-#define DREG_REGID_TRAP_22                      0x0000011EL
-#define DREG_REGID_TRAP_23                      0x0000011FL
-#endif
-#endif
-#define DREG_REGID_RSA0_LOW                     0x00000200L
-#define DREG_REGID_RSA0_HIGH                    0x00000201L
-#define DREG_REGID_RSA1_LOW                     0x00000202L
-#define DREG_REGID_RSA1_HIGH                    0x00000203L
-#define DREG_REGID_RSA2                         0x00000204L
-#define DREG_REGID_RSA3                         0x00000205L
-#define DREG_REGID_RSI0_LOW                     0x00000206L
-#define DREG_REGID_RSI0_HIGH                    0x00000207L
-#define DREG_REGID_RSI1                         0x00000208L
-#define DREG_REGID_RSI2                         0x00000209L
-#define DREG_REGID_SAGUSTATUS                   0x0000020AL
-#define DREG_REGID_RSCONFIG01_LOW               0x0000020BL
-#define DREG_REGID_RSCONFIG01_HIGH              0x0000020CL
-#define DREG_REGID_RSCONFIG23_LOW               0x0000020DL
-#define DREG_REGID_RSCONFIG23_HIGH              0x0000020EL
-#define DREG_REGID_RSDMA01E                     0x0000020FL
-#define DREG_REGID_RSDMA23E                     0x00000210L
-#define DREG_REGID_RSD0_LOW                     0x00000211L
-#define DREG_REGID_RSD0_HIGH                    0x00000212L
-#define DREG_REGID_RSD1_LOW                     0x00000213L
-#define DREG_REGID_RSD1_HIGH                    0x00000214L
-#define DREG_REGID_RSD2_LOW                     0x00000215L
-#define DREG_REGID_RSD2_HIGH                    0x00000216L
-#define DREG_REGID_RSD3_LOW                     0x00000217L
-#define DREG_REGID_RSD3_HIGH                    0x00000218L
-#define DREG_REGID_SRAR_HIGH                    0x0000021AL
-#define DREG_REGID_SRAR_LOW                     0x0000021BL
-#define DREG_REGID_DMA_STATE                    0x0000021CL
-#define DREG_REGID_CURRENT_DMA_STREAM           0x0000021DL
-#define DREG_REGID_NEXT_DMA_STREAM              0x0000021EL
-#define DREG_REGID_CPU_STATUS                   0x00000300L
-#define DREG_REGID_MAC_MODE                     0x00000301L
-#define DREG_REGID_STACK_AND_REPEAT             0x00000302L
-#define DREG_REGID_INDEX0                       0x00000304L
-#define DREG_REGID_INDEX1                       0x00000305L
-#define DREG_REGID_DMA_STATE_0_3                0x00000400L
-#define DREG_REGID_DMA_STATE_4_7                0x00000404L
-#define DREG_REGID_DMA_STATE_8_11               0x00000408L
-#define DREG_REGID_DMA_STATE_12_15              0x0000040CL
-#define DREG_REGID_DMA_STATE_16_19              0x00000410L
-#define DREG_REGID_DMA_STATE_20_23              0x00000414L
-#define DREG_REGID_DMA_STATE_24_27              0x00000418L
-#define DREG_REGID_DMA_STATE_28_31              0x0000041CL
-#define DREG_REGID_DMA_STATE_32_35              0x00000420L
-#define DREG_REGID_DMA_STATE_36_39              0x00000424L
-#define DREG_REGID_DMA_STATE_40_43              0x00000428L
-#define DREG_REGID_DMA_STATE_44_47              0x0000042CL
-#define DREG_REGID_DMA_STATE_48_51              0x00000430L
-#define DREG_REGID_DMA_STATE_52_55              0x00000434L
-#define DREG_REGID_DMA_STATE_56_59              0x00000438L
-#define DREG_REGID_DMA_STATE_60_63              0x0000043CL
-#define DREG_REGID_DMA_STATE_64_67              0x00000440L
-#define DREG_REGID_DMA_STATE_68_71              0x00000444L
-#define DREG_REGID_DMA_STATE_72_75              0x00000448L
-#define DREG_REGID_DMA_STATE_76_79              0x0000044CL
-#define DREG_REGID_DMA_STATE_80_83              0x00000450L
-#define DREG_REGID_DMA_STATE_84_87              0x00000454L
-#define DREG_REGID_DMA_STATE_88_91              0x00000458L
-#define DREG_REGID_DMA_STATE_92_95              0x0000045CL
-#define DREG_REGID_TRAP_SELECT                  0x00000500L
-#define DREG_REGID_TRAP_WRITE_0                 0x00000500L
-#define DREG_REGID_TRAP_WRITE_1                 0x00000501L
-#define DREG_REGID_TRAP_WRITE_2                 0x00000502L
-#define DREG_REGID_TRAP_WRITE_3                 0x00000503L
-#define DREG_REGID_TRAP_WRITE_4                 0x00000504L
-#define DREG_REGID_TRAP_WRITE_5                 0x00000505L
-#define DREG_REGID_TRAP_WRITE_6                 0x00000506L
-#define DREG_REGID_TRAP_WRITE_7                 0x00000507L
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_WRITE_8                 0x00000510L
-#define DREG_REGID_TRAP_WRITE_9                 0x00000511L
-#define DREG_REGID_TRAP_WRITE_10                0x00000512L
-#define DREG_REGID_TRAP_WRITE_11                0x00000513L
-#define DREG_REGID_TRAP_WRITE_12                0x00000514L
-#define DREG_REGID_TRAP_WRITE_13                0x00000515L
-#define DREG_REGID_TRAP_WRITE_14                0x00000516L
-#define DREG_REGID_TRAP_WRITE_15                0x00000517L
-#define DREG_REGID_TRAP_WRITE_16                0x00000518L
-#define DREG_REGID_TRAP_WRITE_17                0x00000519L
-#define DREG_REGID_TRAP_WRITE_18                0x0000051AL
-#define DREG_REGID_TRAP_WRITE_19                0x0000051BL
-#define DREG_REGID_TRAP_WRITE_20                0x0000051CL
-#define DREG_REGID_TRAP_WRITE_21                0x0000051DL
-#define DREG_REGID_TRAP_WRITE_22                0x0000051EL
-#define DREG_REGID_TRAP_WRITE_23                0x0000051FL
-#endif
-#endif
-#define DREG_REGID_MAC0_ACC0_LOW                0x00000600L
-#define DREG_REGID_MAC0_ACC1_LOW                0x00000601L
-#define DREG_REGID_MAC0_ACC2_LOW                0x00000602L
-#define DREG_REGID_MAC0_ACC3_LOW                0x00000603L
-#define DREG_REGID_MAC1_ACC0_LOW                0x00000604L
-#define DREG_REGID_MAC1_ACC1_LOW                0x00000605L
-#define DREG_REGID_MAC1_ACC2_LOW                0x00000606L
-#define DREG_REGID_MAC1_ACC3_LOW                0x00000607L
-#define DREG_REGID_MAC0_ACC0_MID                0x00000608L
-#define DREG_REGID_MAC0_ACC1_MID                0x00000609L
-#define DREG_REGID_MAC0_ACC2_MID                0x0000060AL
-#define DREG_REGID_MAC0_ACC3_MID                0x0000060BL
-#define DREG_REGID_MAC1_ACC0_MID                0x0000060CL
-#define DREG_REGID_MAC1_ACC1_MID                0x0000060DL
-#define DREG_REGID_MAC1_ACC2_MID                0x0000060EL
-#define DREG_REGID_MAC1_ACC3_MID                0x0000060FL
-#define DREG_REGID_MAC0_ACC0_HIGH               0x00000610L
-#define DREG_REGID_MAC0_ACC1_HIGH               0x00000611L
-#define DREG_REGID_MAC0_ACC2_HIGH               0x00000612L
-#define DREG_REGID_MAC0_ACC3_HIGH               0x00000613L
-#define DREG_REGID_MAC1_ACC0_HIGH               0x00000614L
-#define DREG_REGID_MAC1_ACC1_HIGH               0x00000615L
-#define DREG_REGID_MAC1_ACC2_HIGH               0x00000616L
-#define DREG_REGID_MAC1_ACC3_HIGH               0x00000617L
-#define DREG_REGID_RSHOUT_LOW                   0x00000620L
-#define DREG_REGID_RSHOUT_MID                   0x00000628L
-#define DREG_REGID_RSHOUT_HIGH                  0x00000630L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 S/PDIF Control register.
-//
-//****************************************************************************
-#define SPDIF_CONTROL_SPDIF_EN                 0x00008000L
-#define SPDIF_CONTROL_VAL                      0x00004000L
-#define SPDIF_CONTROL_COPY                     0x00000004L
-#define SPDIF_CONTROL_CC0                      0x00000010L
-#define SPDIF_CONTROL_CC1                      0x00000020L
-#define SPDIF_CONTROL_CC2                      0x00000040L
-#define SPDIF_CONTROL_CC3                      0x00000080L
-#define SPDIF_CONTROL_CC4                      0x00000100L
-#define SPDIF_CONTROL_CC5                      0x00000200L
-#define SPDIF_CONTROL_CC6                      0x00000400L
-#define SPDIF_CONTROL_L                        0x00000800L
-
-#endif // _H_HWDEFS
diff --git a/sound/oss/cs4281/cs4281_wrapper-24.c b/sound/oss/cs4281/cs4281_wrapper-24.c
deleted file mode 100644
index 4559f02..0000000
--- a/sound/oss/cs4281/cs4281_wrapper-24.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
-*
-*      "cs4281_wrapper.c" --  Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-*      Copyright (C) 2000,2001  Cirrus Logic Corp.  
-*            -- tom woller (twoller@crystal.cirrus.com) or
-*               (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* 12/20/00 trw - new file. 
-*
-*******************************************************************************/
-
-#include <linux/spinlock.h>
-
-static int cs4281_resume_null(struct pci_dev *pcidev) { return 0; }
-static int cs4281_suspend_null(struct pci_dev *pcidev, pm_message_t state) { return 0; }
-
-#define free_dmabuf(state, dmabuf) \
-	pci_free_consistent(state->pcidev, \
-			    PAGE_SIZE << (dmabuf)->buforder, \
-			    (dmabuf)->rawbuf, (dmabuf)->dmaaddr);
-#define free_dmabuf2(state, dmabuf) \
-	pci_free_consistent((state)->pcidev, \
-				    PAGE_SIZE << (state)->buforder_tmpbuff, \
-				    (state)->tmpbuff, (state)->dmaaddr_tmpbuff);
-#define cs4x_pgoff(vma) ((vma)->vm_pgoff)
-
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
deleted file mode 100644
index 0400a41..0000000
--- a/sound/oss/cs4281/cs4281m.c
+++ /dev/null
@@ -1,4487 +0,0 @@
-/*******************************************************************************
-*
-*      "cs4281.c" --  Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-*      Copyright (C) 2000,2001  Cirrus Logic Corp.  
-*            -- adapted from drivers by Thomas Sailer, 
-*            -- but don't bug him; Problems should go to:
-*            -- tom woller (twoller@crystal.cirrus.com) or
-*               (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* Module command line parameters:
-*   none
-*
-*  Supported devices:
-*  /dev/dsp    standard /dev/dsp device, (mostly) OSS compatible
-*  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
-*  /dev/midi   simple MIDI UART interface, no ioctl
-*
-* Modification History
-* 08/20/00 trw - silence and no stopping DAC until release
-* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop.
-* 09/18/00 trw - added 16bit only record with conversion 
-* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous 
-*                capture/playback rates)
-* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin  
-*                libOSSm.so)
-* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal)
-* 11/03/00 trw - fixed interrupt loss/stutter, added debug.
-* 11/10/00 bkz - added __devinit to cs4281_hw_init()
-* 11/10/00 trw - fixed SMP and capture spinlock hang.
-* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm.
-* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix.
-* 12/08/00 trw - added PM support. 
-* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8 
-*		 (RH/Dell base), 2.2.18, 2.2.12.  cleaned up code mods by ident.
-* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup.
-* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use 
-*		 defaultorder-100 as power of 2 for the buffer size. example:
-*		 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
-*
-*******************************************************************************/
-
-/* uncomment the following line to disable building PM support into the driver */
-//#define NOT_CS4281_PM 1 
-
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/wait.h>
-
-#include <asm/current.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-//#include "cs_dm.h"
-#include "cs4281_hwdefs.h"
-#include "cs4281pm.h"
-
-struct cs4281_state;
-
-static void stop_dac(struct cs4281_state *s);
-static void stop_adc(struct cs4281_state *s);
-static void start_dac(struct cs4281_state *s);
-static void start_adc(struct cs4281_state *s);
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-// --------------------------------------------------------------------- 
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS          0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281
-#define PCI_DEVICE_ID_CRYSTAL_CS4281  0x6005
-#endif
-
-#define CS4281_MAGIC  ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)
-#define	CS4281_CFLR_DEFAULT	0x00000001  /* CFLR must be in AC97 link mode */
-
-// buffer order determines the size of the dma buffer for the driver.
-// under Linux, a smaller buffer allows more responsiveness from many of the 
-// applications (e.g. games).  A larger buffer allows some of the apps (esound) 
-// to not underrun the dma buffer as easily.  As default, use 32k (order=3)
-// rather than 64k as some of the games work more responsively.
-// log base 2( buff sz = 32k).
-static unsigned long defaultorder = 3;
-module_param(defaultorder, ulong, 0);
-
-//
-// Turn on/off debugging compilation by commenting out "#define CSDEBUG"
-//
-#define CSDEBUG 1
-#if CSDEBUG
-#define CSDEBUG_INTERFACE 1
-#else
-#undef CSDEBUG_INTERFACE
-#endif
-//
-// cs_debugmask areas
-//
-#define CS_INIT	 	0x00000001	// initialization and probe functions
-#define CS_ERROR 	0x00000002	// tmp debugging bit placeholder
-#define CS_INTERRUPT	0x00000004	// interrupt handler (separate from all other)
-#define CS_FUNCTION 	0x00000008	// enter/leave functions
-#define CS_WAVE_WRITE 	0x00000010	// write information for wave
-#define CS_WAVE_READ 	0x00000020	// read information for wave
-#define CS_MIDI_WRITE 	0x00000040	// write information for midi
-#define CS_MIDI_READ 	0x00000080	// read information for midi
-#define CS_MPU401_WRITE 0x00000100	// write information for mpu401
-#define CS_MPU401_READ 	0x00000200	// read information for mpu401
-#define CS_OPEN		0x00000400	// all open functions in the driver
-#define CS_RELEASE	0x00000800	// all release functions in the driver
-#define CS_PARMS	0x00001000	// functional and operational parameters
-#define CS_IOCTL	0x00002000	// ioctl (non-mixer)
-#define CS_PM		0x00004000	// power management 
-#define CS_TMP		0x10000000	// tmp debug mask bit
-
-#define CS_IOCTL_CMD_SUSPEND	0x1	// suspend
-#define CS_IOCTL_CMD_RESUME	0x2	// resume
-//
-// CSDEBUG is usual mode is set to 1, then use the
-// cs_debuglevel and cs_debugmask to turn on or off debugging.
-// Debug level of 1 has been defined to be kernel errors and info
-// that should be printed on any released driver.
-//
-#if CSDEBUG
-#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;}
-#else
-#define CS_DBGOUT(mask,level,x)
-#endif
-
-#if CSDEBUG
-static unsigned long cs_debuglevel = 1;	// levels range from 1-9
-static unsigned long cs_debugmask = CS_INIT | CS_ERROR;	// use CS_DBGOUT with various mask values
-module_param(cs_debuglevel, ulong, 0);
-module_param(cs_debugmask, ulong, 0);
-#endif
-#define CS_TRUE 	1
-#define CS_FALSE 	0
-
-// MIDI buffer sizes 
-#define MIDIINBUF  500
-#define MIDIOUTBUF 500
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define CS4281_MAJOR_VERSION 	1
-#define CS4281_MINOR_VERSION 	13
-#ifdef __ia64__
-#define CS4281_ARCH	     	64	//architecture key
-#else
-#define CS4281_ARCH	     	32	//architecture key
-#endif
-
-#define CS_TYPE_ADC 0
-#define CS_TYPE_DAC 1
-
-
-static const char invalid_magic[] =
-    KERN_CRIT "cs4281: invalid magic value\n";
-
-#define VALIDATE_STATE(s)                         \
-({                                                \
-        if (!(s) || (s)->magic != CS4281_MAGIC) { \
-                printk(invalid_magic);            \
-                return -ENXIO;                    \
-        }                                         \
-})
-
-//LIST_HEAD(cs4281_devs);
-static struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs };
-
-struct cs4281_state; 
-
-#include "cs4281_wrapper-24.c"
-
-struct cs4281_state {
-	// magic 
-	unsigned int magic;
-
-	// we keep the cards in a linked list 
-	struct cs4281_state *next;
-
-	// pcidev is needed to turn off the DDMA controller at driver shutdown 
-	struct pci_dev *pcidev;
-	struct list_head list;
-
-	// soundcore stuff 
-	int dev_audio;
-	int dev_mixer;
-	int dev_midi;
-
-	// hardware resources 
-	unsigned int pBA0phys, pBA1phys;
-	char __iomem *pBA0;
-	char __iomem *pBA1;
-	unsigned int irq;
-
-	// mixer registers 
-	struct {
-		unsigned short vol[10];
-		unsigned int recsrc;
-		unsigned int modcnt;
-		unsigned short micpreamp;
-	} mix;
-
-	// wave stuff   
-	struct properties {
-		unsigned fmt;
-		unsigned fmt_original;	// original requested format
-		unsigned channels;
-		unsigned rate;
-		unsigned char clkdiv;
-	} prop_dac, prop_adc;
-	unsigned conversion:1;	// conversion from 16 to 8 bit in progress
-	void *tmpbuff;		// tmp buffer for sample conversions
-	unsigned ena;
-	spinlock_t lock;
-	struct mutex open_sem;
-	struct mutex open_sem_adc;
-	struct mutex open_sem_dac;
-	mode_t open_mode;
-	wait_queue_head_t open_wait;
-	wait_queue_head_t open_wait_adc;
-	wait_queue_head_t open_wait_dac;
-
-	dma_addr_t dmaaddr_tmpbuff;
-	unsigned buforder_tmpbuff;	// Log base 2 of 'rawbuf' size in bytes..
-	struct dmabuf {
-		void *rawbuf;	// Physical address of  
-		dma_addr_t dmaaddr;
-		unsigned buforder;	// Log base 2 of 'rawbuf' size in bytes..
-		unsigned numfrag;	// # of 'fragments' in the buffer.
-		unsigned fragshift;	// Log base 2 of fragment size.
-		unsigned hwptr, swptr;
-		unsigned total_bytes;	// # bytes process since open.
-		unsigned blocks;	// last returned blocks value GETOPTR
-		unsigned wakeup;	// interrupt occurred on block 
-		int count;
-		unsigned underrun;	// underrun flag
-		unsigned error;	// over/underrun 
-		wait_queue_head_t wait;
-		// redundant, but makes calculations easier 
-		unsigned fragsize;	// 2**fragshift..
-		unsigned dmasize;	// 2**buforder.
-		unsigned fragsamples;
-		// OSS stuff 
-		unsigned mapped:1;	// Buffer mapped in cs4281_mmap()?
-		unsigned ready:1;	// prog_dmabuf_dac()/adc() successful?
-		unsigned endcleared:1;
-		unsigned type:1;	// adc or dac buffer (CS_TYPE_XXX)
-		unsigned ossfragshift;
-		int ossmaxfrags;
-		unsigned subdivision;
-	} dma_dac, dma_adc;
-
-	// midi stuff 
-	struct {
-		unsigned ird, iwr, icnt;
-		unsigned ord, owr, ocnt;
-		wait_queue_head_t iwait;
-		wait_queue_head_t owait;
-		struct timer_list timer;
-		unsigned char ibuf[MIDIINBUF];
-		unsigned char obuf[MIDIOUTBUF];
-	} midi;
-
-	struct cs4281_pm pm;
-	struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES];
-};
-
-#include "cs4281pm-24.c"
-
-#if CSDEBUG
-
-// DEBUG ROUTINES
-
-#define SOUND_MIXER_CS_GETDBGLEVEL 	_SIOWR('M',120, int)
-#define SOUND_MIXER_CS_SETDBGLEVEL 	_SIOWR('M',121, int)
-#define SOUND_MIXER_CS_GETDBGMASK 	_SIOWR('M',122, int)
-#define SOUND_MIXER_CS_SETDBGMASK 	_SIOWR('M',123, int)
-
-#define SOUND_MIXER_CS_APM	 	_SIOWR('M',124, int)
-
-
-static void cs_printioctl(unsigned int x)
-{
-	unsigned int i;
-	unsigned char vidx;
-	// Index of mixtable1[] member is Device ID 
-	// and must be <= SOUND_MIXER_NRDEVICES.
-	// Value of array member is index into s->mix.vol[]
-	static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
-		[SOUND_MIXER_PCM] = 1,	// voice 
-		[SOUND_MIXER_LINE1] = 2,	// AUX
-		[SOUND_MIXER_CD] = 3,	// CD 
-		[SOUND_MIXER_LINE] = 4,	// Line 
-		[SOUND_MIXER_SYNTH] = 5,	// FM
-		[SOUND_MIXER_MIC] = 6,	// Mic 
-		[SOUND_MIXER_SPEAKER] = 7,	// Speaker 
-		[SOUND_MIXER_RECLEV] = 8,	// Recording level 
-		[SOUND_MIXER_VOLUME] = 9	// Master Volume 
-	};
-
-	switch (x) {
-	case SOUND_MIXER_CS_GETDBGMASK:
-		CS_DBGOUT(CS_IOCTL, 4,
-			  printk("SOUND_MIXER_CS_GETDBGMASK:\n"));
-		break;
-	case SOUND_MIXER_CS_GETDBGLEVEL:
-		CS_DBGOUT(CS_IOCTL, 4,
-			  printk("SOUND_MIXER_CS_GETDBGLEVEL:\n"));
-		break;
-	case SOUND_MIXER_CS_SETDBGMASK:
-		CS_DBGOUT(CS_IOCTL, 4,
-			  printk("SOUND_MIXER_CS_SETDBGMASK:\n"));
-		break;
-	case SOUND_MIXER_CS_SETDBGLEVEL:
-		CS_DBGOUT(CS_IOCTL, 4,
-			  printk("SOUND_MIXER_CS_SETDBGLEVEL:\n"));
-		break;
-	case OSS_GETVERSION:
-		CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n"));
-		break;
-	case SNDCTL_DSP_SYNC:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n"));
-		break;
-	case SNDCTL_DSP_SETDUPLEX:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n"));
-		break;
-	case SNDCTL_DSP_GETCAPS:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n"));
-		break;
-	case SNDCTL_DSP_RESET:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n"));
-		break;
-	case SNDCTL_DSP_SPEED:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n"));
-		break;
-	case SNDCTL_DSP_STEREO:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n"));
-		break;
-	case SNDCTL_DSP_CHANNELS:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n"));
-		break;
-	case SNDCTL_DSP_GETFMTS:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n"));
-		break;
-	case SNDCTL_DSP_SETFMT:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n"));
-		break;
-	case SNDCTL_DSP_POST:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n"));
-		break;
-	case SNDCTL_DSP_GETTRIGGER:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n"));
-		break;
-	case SNDCTL_DSP_SETTRIGGER:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n"));
-		break;
-	case SNDCTL_DSP_GETOSPACE:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n"));
-		break;
-	case SNDCTL_DSP_GETISPACE:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n"));
-		break;
-	case SNDCTL_DSP_NONBLOCK:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n"));
-		break;
-	case SNDCTL_DSP_GETODELAY:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n"));
-		break;
-	case SNDCTL_DSP_GETIPTR:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n"));
-		break;
-	case SNDCTL_DSP_GETOPTR:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n"));
-		break;
-	case SNDCTL_DSP_GETBLKSIZE:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n"));
-		break;
-	case SNDCTL_DSP_SETFRAGMENT:
-		CS_DBGOUT(CS_IOCTL, 4,
-			  printk("SNDCTL_DSP_SETFRAGMENT:\n"));
-		break;
-	case SNDCTL_DSP_SUBDIVIDE:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n"));
-		break;
-	case SOUND_PCM_READ_RATE:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n"));
-		break;
-	case SOUND_PCM_READ_CHANNELS:
-		CS_DBGOUT(CS_IOCTL, 4,
-			  printk("SOUND_PCM_READ_CHANNELS:\n"));
-		break;
-	case SOUND_PCM_READ_BITS:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n"));
-		break;
-	case SOUND_PCM_WRITE_FILTER:
-		CS_DBGOUT(CS_IOCTL, 4,
-			  printk("SOUND_PCM_WRITE_FILTER:\n"));
-		break;
-	case SNDCTL_DSP_SETSYNCRO:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n"));
-		break;
-	case SOUND_PCM_READ_FILTER:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n"));
-		break;
-	case SOUND_MIXER_PRIVATE1:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n"));
-		break;
-	case SOUND_MIXER_PRIVATE2:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n"));
-		break;
-	case SOUND_MIXER_PRIVATE3:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n"));
-		break;
-	case SOUND_MIXER_PRIVATE4:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n"));
-		break;
-	case SOUND_MIXER_PRIVATE5:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n"));
-		break;
-	case SOUND_MIXER_INFO:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n"));
-		break;
-	case SOUND_OLD_MIXER_INFO:
-		CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n"));
-		break;
-
-	default:
-		switch (_IOC_NR(x)) {
-		case SOUND_MIXER_VOLUME:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_VOLUME:\n"));
-			break;
-		case SOUND_MIXER_SPEAKER:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_SPEAKER:\n"));
-			break;
-		case SOUND_MIXER_RECLEV:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_RECLEV:\n"));
-			break;
-		case SOUND_MIXER_MIC:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_MIC:\n"));
-			break;
-		case SOUND_MIXER_SYNTH:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_SYNTH:\n"));
-			break;
-		case SOUND_MIXER_RECSRC:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_RECSRC:\n"));
-			break;
-		case SOUND_MIXER_DEVMASK:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_DEVMASK:\n"));
-			break;
-		case SOUND_MIXER_RECMASK:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_RECMASK:\n"));
-			break;
-		case SOUND_MIXER_STEREODEVS:
-			CS_DBGOUT(CS_IOCTL, 4,
-				  printk("SOUND_MIXER_STEREODEVS:\n"));
-			break;
-		case SOUND_MIXER_CAPS:
-			CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n"));
-			break;
-		default:
-			i = _IOC_NR(x);
-			if (i >= SOUND_MIXER_NRDEVICES
-			    || !(vidx = mixtable1[i])) {
-				CS_DBGOUT(CS_IOCTL, 4, printk
-					("UNKNOWN IOCTL: 0x%.8x NR=%d\n",
-						x, i));
-			} else {
-				CS_DBGOUT(CS_IOCTL, 4, printk
-					("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n",
-						x, i));
-			}
-			break;
-		}
-	}
-}
-#endif
-static int prog_dmabuf_adc(struct cs4281_state *s);
-static void prog_codec(struct cs4281_state *s, unsigned type);
-
-// --------------------------------------------------------------------- 
-//
-//              Hardware Interfaces For the CS4281
-//
-
-
-//******************************************************************************
-// "delayus()-- Delay for the specified # of microseconds.
-//******************************************************************************
-static void delayus(struct cs4281_state *s, u32 delay)
-{
-	u32 j;
-	if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) {
-		j = (delay * HZ) / 1000000;	/* calculate delay in jiffies  */
-		if (j < 1)
-			j = 1;	/* minimum one jiffy. */
-		current->state = TASK_UNINTERRUPTIBLE;
-		schedule_timeout(j);
-	} else
-		udelay(delay);
-	return;
-}
-
-
-//******************************************************************************
-// "cs4281_read_ac97" -- Reads a word from the specified location in the
-//               CS4281's address space(based on the BA0 register).
-//
-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register,
-//                                            0h for reads.
-// 3. Write ACCTL = Control Register = 460h for initiating the write
-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
-// 5. if DCV not cleared, break and return error
-// 6. Read ACSTS = Status Register = 464h, check VSTS bit
-//****************************************************************************
-static int cs4281_read_ac97(struct cs4281_state *card, u32 offset,
-			    u32 * value)
-{
-	u32 count, status;
-
-	// Make sure that there is not data sitting
-	// around from a previous uncompleted access.
-	// ACSDA = Status Data Register = 47Ch
-	status = readl(card->pBA0 + BA0_ACSDA);
-
-	// Setup the AC97 control registers on the CS4281 to send the
-	// appropriate command to the AC97 to perform the read.
-	// ACCAD = Command Address Register = 46Ch
-	// ACCDA = Command Data Register = 470h
-	// ACCTL = Control Register = 460h
-	// bit DCV - will clear when process completed
-	// bit CRW - Read command
-	// bit VFRM - valid frame enabled
-	// bit ESYN - ASYNC generation enabled
-
-	// Get the actual AC97 register from the offset
-	writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
-	writel(0, card->pBA0 + BA0_ACCDA);
-	writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN,
-	       card->pBA0 + BA0_ACCTL);
-
-	// Wait for the read to occur.
-	for (count = 0; count < 10; count++) {
-		// First, we want to wait for a short time.
-		udelay(25);
-
-		// Now, check to see if the read has completed.
-		// ACCTL = 460h, DCV should be reset by now and 460h = 17h
-		if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV))
-			break;
-	}
-
-	// Make sure the read completed.
-	if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)
-		return 1;
-
-	// Wait for the valid status bit to go active.
-	for (count = 0; count < 10; count++) {
-		// Read the AC97 status register.
-		// ACSTS = Status Register = 464h
-		status = readl(card->pBA0 + BA0_ACSTS);
-
-		// See if we have valid status.
-		// VSTS - Valid Status
-		if (status & ACSTS_VSTS)
-			break;
-		// Wait for a short while.
-		udelay(25);
-	}
-
-	// Make sure we got valid status.
-	if (!(status & ACSTS_VSTS))
-		return 1;
-
-	// Read the data returned from the AC97 register.
-	// ACSDA = Status Data Register = 474h
-	*value = readl(card->pBA0 + BA0_ACSDA);
-
-	// Success.
-	return (0);
-}
-
-
-//****************************************************************************
-//
-// "cs4281_write_ac97()"-- writes a word to the specified location in the
-// CS461x's address space (based on the part's base address zero register).
-//
-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg.
-// 3. Write ACCTL = Control Register = 460h for initiating the write
-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
-// 5. if DCV not cleared, break and return error
-//
-//****************************************************************************
-static int cs4281_write_ac97(struct cs4281_state *card, u32 offset,
-			     u32 value)
-{
-	u32 count, status=0;
-
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n"));
-
-	// Setup the AC97 control registers on the CS4281 to send the
-	// appropriate command to the AC97 to perform the read.
-	// ACCAD = Command Address Register = 46Ch
-	// ACCDA = Command Data Register = 470h
-	// ACCTL = Control Register = 460h
-	// set DCV - will clear when process completed
-	// reset CRW - Write command
-	// set VFRM - valid frame enabled
-	// set ESYN - ASYNC generation enabled
-	// set RSTN - ARST# inactive, AC97 codec not reset
-
-	// Get the actual AC97 register from the offset
-
-	writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
-	writel(value, card->pBA0 + BA0_ACCDA);
-	writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN,
-	       card->pBA0 + BA0_ACCTL);
-
-	// Wait for the write to occur.
-	for (count = 0; count < 100; count++) {
-		// First, we want to wait for a short time.
-		udelay(25);
-		// Now, check to see if the write has completed.
-		// ACCTL = 460h, DCV should be reset by now and 460h = 07h
-		status = readl(card->pBA0 + BA0_ACCTL);
-		if (!(status & ACCTL_DCV))
-			break;
-	}
-
-	// Make sure the write completed.
-	if (status & ACCTL_DCV) {
-		CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
-	      		"cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n"));
-		return 1;
-	}
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n"));
-	// Success.
-	return 0;
-}
-
-
-//******************************************************************************
-// "Init4281()" -- Bring up the part.
-//******************************************************************************
-static __devinit int cs4281_hw_init(struct cs4281_state *card)
-{
-	u32 ac97_slotid;
-	u32 temp1, temp2;
-
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n"));
-#ifndef NOT_CS4281_PM
-	if(!card)
-		return 1;
-#endif
-	temp2 = readl(card->pBA0 + BA0_CFLR);
-	CS_DBGOUT(CS_INIT | CS_ERROR | CS_PARMS, 4, printk(KERN_INFO 
-		"cs4281: cs4281_hw_init() CFLR 0x%x\n", temp2));
-	if(temp2 != CS4281_CFLR_DEFAULT)
-	{
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO 
-			"cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n",
-				temp2,CS4281_CFLR_DEFAULT));
-		writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR);
-		temp2 = readl(card->pBA0 + BA0_CFLR);
-		if(temp2 != CS4281_CFLR_DEFAULT)
-		{
-			CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO 
-				"cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n"));
-			return 1;
-		}
-	}
-
-	//***************************************7
-	//  Set up the Sound System Configuration
-	//***************************************
-
-	// Set the 'Configuration Write Protect' register
-	// to 4281h.  Allows vendor-defined configuration
-	// space between 0e4h and 0ffh to be written.
-
-	writel(0x4281, card->pBA0 + BA0_CWPR);	// (3e0h)
-
-	// (0), Blast the clock control register to zero so that the
-	// PLL starts out in a known state, and blast the master serial
-	// port control register to zero so that the serial ports also
-	// start out in a known state.
-
-	writel(0, card->pBA0 + BA0_CLKCR1);	// (400h)
-	writel(0, card->pBA0 + BA0_SERMC);	// (420h)
-
-
-	// (1), Make ESYN go to zero to turn off
-	// the Sync pulse on the AC97 link.
-
-	writel(0, card->pBA0 + BA0_ACCTL);
-	udelay(50);
-
-
-	// (2) Drive the ARST# pin low for a minimum of 1uS (as defined in
-	// the AC97 spec) and then drive it high.  This is done for non
-	// AC97 modes since there might be logic external to the CS461x
-	// that uses the ARST# line for a reset.
-
-	writel(0, card->pBA0 + BA0_SPMC);	// (3ech)
-	udelay(100);
-	writel(SPMC_RSTN, card->pBA0 + BA0_SPMC);
-	delayus(card,50000);		// Wait 50 ms for ABITCLK to become stable.
-
-	// (3) Turn on the Sound System Clocks.
-	writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1);	// (400h)
-	delayus(card,50000);		// Wait for the PLL to stabilize.
-	// Turn on clocking of the core (CLKCR1(400h) = 0x00000030)
-	writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1);
-
-	// (4) Power on everything for now..
-	writel(0x7E, card->pBA0 + BA0_SSPM);	// (740h)
-
-	// (5) Wait for clock stabilization.
-	for (temp1 = 0; temp1 < 1000; temp1++) {
-		udelay(1000);
-		if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)
-			break;
-	}
-	if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) {
-		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR 
-			"cs4281: DLLRDY failed!\n"));
-		return -EIO;
-	}
-	// (6) Enable ASYNC generation.
-	writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL);	// (460h)
-
-	// Now wait 'for a short while' to allow the  AC97
-	// part to start generating bit clock. (so we don't
-	// Try to start the PLL without an input clock.)
-	delayus(card,50000);
-
-	// Set the serial port timing configuration, so that the
-	// clock control circuit gets its clock from the right place.
-	writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC);	// (420h)=2.
-
-	// (7) Wait for the codec ready signal from the AC97 codec.
-
-	for (temp1 = 0; temp1 < 1000; temp1++) {
-		// Delay a mil to let things settle out and
-		// to prevent retrying the read too quickly.
-		udelay(1000);
-		if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)	// If ready,  (464h)
-			break;	//   exit the 'for' loop.
-	}
-	if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY))	// If never came ready,
-	{
-		CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
-			 "cs4281: ACSTS never came ready!\n"));
-		return -EIO;	//   exit initialization.
-	}
-	// (8) Assert the 'valid frame' signal so we can
-	// begin sending commands to the AC97 codec.
-	writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL);	// (460h)
-
-	// (9), Wait until CODEC calibration is finished.
-	// Print an error message if it doesn't.
-	for (temp1 = 0; temp1 < 1000; temp1++) {
-		delayus(card,10000);
-		// Read the AC97 Powerdown Control/Status Register.
-		cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2);
-		if ((temp2 & 0x0000000F) == 0x0000000F)
-			break;
-	}
-	if ((temp2 & 0x0000000F) != 0x0000000F) {
-		CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
-			"cs4281: Codec failed to calibrate.  Status = %.8x.\n",
-				temp2));
-		return -EIO;
-	}
-	// (10), Set the serial port timing configuration, so that the
-	// clock control circuit gets its clock from the right place.
-	writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC);	// (420h)=2.
-
-
-	// (11) Wait until we've sampled input slots 3 & 4 as valid, meaning
-	// that the codec is pumping ADC data across the AC link.
-	for (temp1 = 0; temp1 < 1000; temp1++) {
-		// Delay a mil to let things settle out and
-		// to prevent retrying the read too quickly.
-		delayus(card,1000);	//(test)
-
-		// Read the input slot valid register;  See
-		// if input slots 3 and 4 are valid yet.
-		if (
-		    (readl(card->pBA0 + BA0_ACISV) &
-		     (ACISV_ISV3 | ACISV_ISV4)) ==
-		    (ACISV_ISV3 | ACISV_ISV4)) break;	// Exit the 'for' if slots are valid.
-	}
-	// If we never got valid data, exit initialization.
-	if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4))
-	    != (ACISV_ISV3 | ACISV_ISV4)) {
-		CS_DBGOUT(CS_FUNCTION, 2,
-			  printk(KERN_ERR
-				 "cs4281: Never got valid data!\n"));
-		return -EIO;	// If no valid data, exit initialization.
-	}
-	// (12), Start digital data transfer of audio data to the codec.
-	writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV);	// (468h)
-
-
-	//**************************************
-	// Unmute the Master and Alternate
-	// (headphone) volumes.  Set to max.
-	//**************************************
-	cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0);
-	cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0);
-
-	//******************************************
-	// Power on the DAC(AddDACUser()from main())
-	//******************************************
-	cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
-	cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff);
-
-	// Wait until we sample a DAC ready state.
-	for (temp2 = 0; temp2 < 32; temp2++) {
-		// Let's wait a mil to let things settle.
-		delayus(card,1000);
-		// Read the current state of the power control reg.
-		cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
-		// If the DAC ready state bit is set, stop waiting.
-		if (temp1 & 0x2)
-			break;
-	}
-
-	//******************************************
-	// Power on the ADC(AddADCUser()from main())
-	//******************************************
-	cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
-	cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff);
-
-	// Wait until we sample ADC ready state.
-	for (temp2 = 0; temp2 < 32; temp2++) {
-		// Let's wait a mil to let things settle.
-		delayus(card,1000);
-		// Read the current state of the power control reg.
-		cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
-		// If the ADC ready state bit is set, stop waiting.
-		if (temp1 & 0x1)
-			break;
-	}
-	// Set up 4281 Register contents that
-	// don't change for boot duration.
-
-	// For playback, we map AC97 slot 3 and 4(Left
-	// & Right PCM playback) to DMA Channel 0.
-	// Set the fifo to be 15 bytes at offset zero.
-
-	ac97_slotid = 0x01000f00;	// FCR0.RS[4:0]=1(=>slot4, right PCM playback).
-	// FCR0.LS[4:0]=0(=>slot3, left PCM playback).
-	// FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.
-	writel(ac97_slotid, card->pBA0 + BA0_FCR0);	// (180h)
-	writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0);	// Turn on FIFO Enable.
-
-	// For capture, we map AC97 slot 10 and 11(Left
-	// and Right PCM Record) to DMA Channel 1.
-	// Set the fifo to be 15 bytes at offset sixteen.
-	ac97_slotid = 0x0B0A0f10;	// FCR1.RS[4:0]=11(=>slot11, right PCM record).
-	// FCR1.LS[4:0]=10(=>slot10, left PCM record).
-	// FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.
-	writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1);	// (184h)
-	writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1);	// Turn on FIFO Enable.
-
-	// Map the Playback SRC to the same AC97 slots(3 & 4--
-	// --Playback left & right)as DMA channel 0.
-	// Map the record SRC to the same AC97 slots(10 & 11--
-	// -- Record left & right) as DMA channel 1.
-
-	ac97_slotid = 0x0b0a0100;	// SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback).
-	// SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).
-	// SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)
-	// SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).
-	writel(ac97_slotid, card->pBA0 + BA0_SRCSA);	// (75ch)
-
-	// Set 'Half Terminal Count Interrupt Enable' and 'Terminal
-	// Count Interrupt Enable' in DMA Control Registers 0 & 1.
-	// Set 'MSK' flag to 1 to keep the DMA engines paused.
-	temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK);	// (00030001h)
-	writel(temp1, card->pBA0 + BA0_DCR0);	// (154h
-	writel(temp1, card->pBA0 + BA0_DCR1);	// (15ch)
-
-	// Set 'Auto-Initialize Control' to 'enabled'; For playback,
-	// set 'Transfer Type Control'(TR[1:0]) to 'read transfer',
-	// for record, set Transfer Type Control to 'write transfer'.
-	// All other bits set to zero;  Some will be changed @ transfer start.
-	temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ);	// (20000018h)
-	writel(temp1, card->pBA0 + BA0_DMR0);	// (150h)
-	temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE);	// (20000014h)
-	writel(temp1, card->pBA0 + BA0_DMR1);	// (158h)
-
-	// Enable DMA interrupts generally, and
-	// DMA0 & DMA1 interrupts specifically.
-	temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;
-	writel(temp1, card->pBA0 + BA0_HIMR);
-
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n"));
-	return 0;
-}
-
-#ifndef NOT_CS4281_PM
-static void printpm(struct cs4281_state *s)
-{
-	CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
-	CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
-		(unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
-	CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
-		s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
-	CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
-		s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
-	CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
-		s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
-	CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
-		s->pm.u32SSCR,s->pm.u32SRCSA));
-	CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
-		s->pm.u32DacASR,s->pm.u32AdcASR));
-	CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
-		s->pm.u32DacSR,s->pm.u32AdcSR));
-	CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
-		s->pm.u32MIDCR_Save));
-
-}
-static void printpipe(struct cs4281_pipeline *pl)
-{
-
-	CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
-	CS_DBGOUT(CS_PM, 9, printk("flags:0x%x number: 0%x\n",
-		(unsigned)pl->flags,pl->number));
-	CS_DBGOUT(CS_PM, 9, printk("u32DBAnValue: 0%x u32DBCnValue: 0x%x\n",
-		pl->u32DBAnValue,pl->u32DBCnValue));
-	CS_DBGOUT(CS_PM, 9, printk("u32DMRnValue: 0x%x u32DCRnValue: 0x%x\n",
-		pl->u32DMRnValue,pl->u32DCRnValue));
-	CS_DBGOUT(CS_PM, 9, printk("u32DBAnAddress: 0x%x u32DBCnAddress: 0x%x\n",
-		pl->u32DBAnAddress,pl->u32DBCnAddress));
-	CS_DBGOUT(CS_PM, 9, printk("u32DCAnAddress: 0x%x u32DCCnAddress: 0x%x\n",
-		pl->u32DCCnAddress,pl->u32DCCnAddress));
-	CS_DBGOUT(CS_PM, 9, printk("u32DMRnAddress: 0x%x u32DCRnAddress: 0x%x\n",
-		pl->u32DMRnAddress,pl->u32DCRnAddress));
-	CS_DBGOUT(CS_PM, 9, printk("u32HDSRnAddress: 0x%x u32DBAn_Save: 0x%x\n",
-		pl->u32HDSRnAddress,pl->u32DBAn_Save));
-	CS_DBGOUT(CS_PM, 9, printk("u32DBCn_Save: 0x%x u32DMRn_Save: 0x%x\n",
-		pl->u32DBCn_Save,pl->u32DMRn_Save));
-	CS_DBGOUT(CS_PM, 9, printk("u32DCRn_Save: 0x%x u32DCCn_Save: 0x%x\n",
-		pl->u32DCRn_Save,pl->u32DCCn_Save));
-	CS_DBGOUT(CS_PM, 9, printk("u32DCAn_Save: 0x%x\n",
-		pl->u32DCAn_Save));
-	CS_DBGOUT(CS_PM, 9, printk("u32FCRn_Save: 0x%x u32FSICn_Save: 0x%x\n",
-		pl->u32FCRn_Save,pl->u32FSICn_Save));
-	CS_DBGOUT(CS_PM, 9, printk("u32FCRnValue: 0x%x u32FSICnValue: 0x%x\n",
-		pl->u32FCRnValue,pl->u32FSICnValue));
-	CS_DBGOUT(CS_PM, 9, printk("u32FCRnAddress: 0x%x u32FSICnAddress: 0x%x\n",
-		pl->u32FCRnAddress,pl->u32FSICnAddress));
-	CS_DBGOUT(CS_PM, 9, printk("u32FPDRnValue: 0x%x u32FPDRnAddress: 0x%x\n",
-		pl->u32FPDRnValue,pl->u32FPDRnAddress));
-}
-static void printpipelines(struct cs4281_state *s)
-{
-	int i;
-	for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
-	{
-		if(s->pl[i].flags & CS4281_PIPELINE_VALID)
-		{
-			printpipe(&s->pl[i]);
-		}
-	}
-}
-/****************************************************************************
-*
-*  Suspend - save the ac97 regs, mute the outputs and power down the part.  
-*
-****************************************************************************/
-static void cs4281_ac97_suspend(struct cs4281_state *s)
-{
-	int Count,i;
-
-	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()+\n"));
-/*
-* change the state, save the current hwptr, then stop the dac/adc
-*/
-	s->pm.flags &= ~CS4281_PM_IDLE;
-	s->pm.flags |= CS4281_PM_SUSPENDING;
-	s->pm.u32hwptr_playback = readl(s->pBA0 + BA0_DCA0);
-	s->pm.u32hwptr_capture = readl(s->pBA0 + BA0_DCA1);
-	stop_dac(s);
-	stop_adc(s);
-
-	for(Count = 0x2, i=0; (Count <= CS4281_AC97_HIGHESTREGTORESTORE)
-			&& (i < CS4281_AC97_NUMBER_RESTORE_REGS); 
-		Count += 2, i++)
-	{
-		cs4281_read_ac97(s, BA0_AC97_RESET + Count, &s->pm.ac97[i]);
-	}
-/*
-* Save the ac97 volume registers as well as the current powerdown state.
-* Now, mute the all the outputs (master, headphone, and mono), as well
-* as the PCM volume, in preparation for powering down the entire part.
-*/ 
-	cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME, &s->pm.u32AC97_master_volume);
-	cs4281_read_ac97(s, BA0_AC97_HEADPHONE_VOLUME, &s->pm.u32AC97_headphone_volume);
-	cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, &s->pm.u32AC97_master_volume_mono);
-	cs4281_read_ac97(s, BA0_AC97_PCM_OUT_VOLUME, &s->pm.u32AC97_pcm_out_volume);
-		
-	cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, 0x8000);
-	cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, 0x8000);
-	cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
-	cs4281_write_ac97(s, BA0_AC97_PCM_OUT_VOLUME, 0x8000);
-
-	cs4281_read_ac97(s, BA0_AC97_POWERDOWN, &s->pm.u32AC97_powerdown);
-	cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &s->pm.u32AC97_general_purpose);
-
-/*
-* And power down everything on the AC97 codec.
-*/
-	cs4281_write_ac97(s, BA0_AC97_POWERDOWN, 0xff00);
-	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()-\n"));
-}
-
-/****************************************************************************
-*
-*  Resume - power up the part and restore its registers..  
-*
-****************************************************************************/
-static void cs4281_ac97_resume(struct cs4281_state *s)
-{
-	int Count,i;
-
-	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()+\n"));
-
-/* do not save the power state registers at this time
-    //
-    // If we saved away the power control registers, write them into the
-    // shadows so those saved values get restored instead of the current
-    // shadowed value.
-    //
-    if( bPowerStateSaved )
-    {
-        PokeShadow( 0x26, ulSaveReg0x26 );
-        bPowerStateSaved = FALSE;
-    }
-*/
-
-//
-// First, we restore the state of the general purpose register.  This
-// contains the mic select (mic1 or mic2) and if we restore this after
-// we restore the mic volume/boost state and mic2 was selected at
-// suspend time, we will end up with a brief period of time where mic1
-// is selected with the volume/boost settings for mic2, causing
-// acoustic feedback.  So we restore the general purpose register
-// first, thereby getting the correct mic selected before we restore
-// the mic volume/boost.
-//
-	cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE, s->pm.u32AC97_general_purpose);
-
-//
-// Now, while the outputs are still muted, restore the state of power
-// on the AC97 part.
-//
-	cs4281_write_ac97(s, BA0_AC97_POWERDOWN, s->pm.u32AC97_powerdown);
-
-/*
-* Restore just the first set of registers, from register number
-* 0x02 to the register number that ulHighestRegToRestore specifies.
-*/
-	for(	Count = 0x2, i=0; 
-		(Count <= CS4281_AC97_HIGHESTREGTORESTORE)
-			&& (i < CS4281_AC97_NUMBER_RESTORE_REGS); 
-		Count += 2, i++)
-	{
-		cs4281_write_ac97(s, BA0_AC97_RESET + Count, s->pm.ac97[i]);
-	}
-	CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()-\n"));
-}
-
-/* do not save the power state registers at this time
-****************************************************************************
-*
-*  SavePowerState - Save the power registers away. 
-*
-****************************************************************************
-void 
-HWAC97codec::SavePowerState(void)
-{
-    ENTRY(TM_OBJECTCALLS, "HWAC97codec::SavePowerState()\r\n");
-
-    ulSaveReg0x26 = PeekShadow(0x26);
-
-    //
-    // Note that we have saved registers that need to be restored during a
-    // resume instead of ulAC97Regs[].
-    //
-    bPowerStateSaved = TRUE;
-
-} // SavePowerState
-*/
-
-static void cs4281_SuspendFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- /*
- * We need to save the contents of the BASIC FIFO Registers.
- */
-	pl->u32FCRn_Save = readl(s->pBA0 + pl->u32FCRnAddress);
-	pl->u32FSICn_Save = readl(s->pBA0 + pl->u32FSICnAddress);
-}
-static void cs4281_ResumeFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- /*
- * We need to restore the contents of the BASIC FIFO Registers.
- */
-	writel(pl->u32FCRn_Save,s->pBA0 + pl->u32FCRnAddress);
-	writel(pl->u32FSICn_Save,s->pBA0 + pl->u32FSICnAddress);
-}
-static void cs4281_SuspendDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
-	//
-	// We need to save the contents of the BASIC DMA Registers.
-	//
-	pl->u32DBAn_Save = readl(s->pBA0 + pl->u32DBAnAddress);
-	pl->u32DBCn_Save = readl(s->pBA0 + pl->u32DBCnAddress);
-	pl->u32DMRn_Save = readl(s->pBA0 + pl->u32DMRnAddress);
-	pl->u32DCRn_Save = readl(s->pBA0 + pl->u32DCRnAddress);
-	pl->u32DCCn_Save = readl(s->pBA0 + pl->u32DCCnAddress);
-	pl->u32DCAn_Save = readl(s->pBA0 + pl->u32DCAnAddress);
-}
-static void cs4281_ResumeDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
-	//
-	// We need to save the contents of the BASIC DMA Registers.
-	//
-	writel( pl->u32DBAn_Save, s->pBA0 + pl->u32DBAnAddress);
-	writel( pl->u32DBCn_Save, s->pBA0 + pl->u32DBCnAddress);
-	writel( pl->u32DMRn_Save, s->pBA0 + pl->u32DMRnAddress);
-	writel( pl->u32DCRn_Save, s->pBA0 + pl->u32DCRnAddress);
-	writel( pl->u32DCCn_Save, s->pBA0 + pl->u32DCCnAddress);
-	writel( pl->u32DCAn_Save, s->pBA0 + pl->u32DCAnAddress);
-}
-
-static int cs4281_suspend(struct cs4281_state *s)
-{
-	int i;
-	u32 u32CLKCR1;
-	struct cs4281_pm *pm = &s->pm;
-	CS_DBGOUT(CS_PM | CS_FUNCTION, 9, 
-		printk("cs4281: cs4281_suspend()+ flags=%d\n",
-			(unsigned)s->pm.flags));
-/*
-* check the current state, only suspend if IDLE
-*/
-	if(!(s->pm.flags & CS4281_PM_IDLE))
-	{
-		CS_DBGOUT(CS_PM | CS_ERROR, 2, 
-			printk("cs4281: cs4281_suspend() unable to suspend, not IDLE\n"));
-		return 1;
-	}
-	s->pm.flags &= ~CS4281_PM_IDLE;
-	s->pm.flags |= CS4281_PM_SUSPENDING;
-
-//
-// Gershwin CLKRUN - Set CKRA
-//
-	u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
-
-	pm->u32CLKCR1_SAVE = u32CLKCR1;
-	if(!(u32CLKCR1 & 0x00010000 ) )
-		writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
-
-//
-// First, turn on the clocks (yikes) to the devices, so that they will
-// respond when we try to save their state.
-//
-	if(!(u32CLKCR1 & CLKCR1_SWCE))
-	{
-		writel(u32CLKCR1 | CLKCR1_SWCE , s->pBA0 + BA0_CLKCR1);
-	}
-    
-	//
-	// Save the power state
-	//
-	pm->u32SSPMValue = readl(s->pBA0 + BA0_SSPM);
-
-	//
-	// Disable interrupts.
-	//
-	writel(HICR_CHGM, s->pBA0 + BA0_HICR);
-
-	//
-	// Save the PCM Playback Left and Right Volume Control.
-	//
-	pm->u32PPLVCvalue = readl(s->pBA0 + BA0_PPLVC);
-	pm->u32PPRVCvalue = readl(s->pBA0 + BA0_PPRVC);
-
-	//
-	// Save the FM Synthesis Left and Right Volume Control.
-	//
-	pm->u32FMLVCvalue = readl(s->pBA0 + BA0_FMLVC);
-	pm->u32FMRVCvalue = readl(s->pBA0 + BA0_FMRVC);
-
-	//
-	// Save the GPIOR value.
-	//
-	pm->u32GPIORvalue = readl(s->pBA0 + BA0_GPIOR);
-
-	//
-	// Save the JSCTL value.
-	//
-	pm->u32JSCTLvalue = readl(s->pBA0 + BA0_GPIOR);
-
-	//
-	// Save Sound System Control Register
-	//
-	pm->u32SSCR = readl(s->pBA0 + BA0_SSCR);
-
-	//
-	// Save SRC Slot Assinment register
-	//
-	pm->u32SRCSA = readl(s->pBA0 + BA0_SRCSA);
-
-	//
-	// Save sample rate
-	//
-	pm->u32DacASR = readl(s->pBA0 + BA0_PASR);
-	pm->u32AdcASR = readl(s->pBA0 + BA0_CASR);
-	pm->u32DacSR = readl(s->pBA0 + BA0_DACSR);
-	pm->u32AdcSR = readl(s->pBA0 + BA0_ADCSR);
-
-	//
-	// Loop through all of the PipeLines 
-	//
-	for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
-        {
-		if(s->pl[i].flags & CS4281_PIPELINE_VALID)
-		{
-		//
-		// Ask the DMAengines and FIFOs to Suspend.
-		//
-			cs4281_SuspendDMAengine(s,&s->pl[i]);
-			cs4281_SuspendFIFO(s,&s->pl[i]);
-		}
-	}
-	//
-	// We need to save the contents of the Midi Control Register.
-	//
-	pm->u32MIDCR_Save = readl(s->pBA0 + BA0_MIDCR);
-/*
-* save off the AC97 part information
-*/
-	cs4281_ac97_suspend(s);
-    
-	//
-	// Turn off the serial ports.
-	//
-	writel(0, s->pBA0 + BA0_SERMC);
-
-	//
-	// Power off FM, Joystick, AC link, 
-	//
-	writel(0, s->pBA0 + BA0_SSPM);
-
-	//
-	// DLL off.
-	//
-	writel(0, s->pBA0 + BA0_CLKCR1);
-
-	//
-	// AC link off.
-	//
-	writel(0, s->pBA0 + BA0_SPMC);
-
-	//
-	// Put the chip into D3(hot) state.
-	//
-	// PokeBA0(BA0_PMCS, 0x00000003);
-
-	//
-	// Gershwin CLKRUN - Clear CKRA
-	//
-	u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
-	writel(u32CLKCR1 & 0xFFFEFFFF, s->pBA0 + BA0_CLKCR1);
-
-#ifdef CSDEBUG
-	printpm(s);
-	printpipelines(s);
-#endif
-
-	s->pm.flags &= ~CS4281_PM_SUSPENDING;
-	s->pm.flags |= CS4281_PM_SUSPENDED;
-
-	CS_DBGOUT(CS_PM | CS_FUNCTION, 9, 
-		printk("cs4281: cs4281_suspend()- flags=%d\n",
-			(unsigned)s->pm.flags));
-	return 0;
-}
-
-static int cs4281_resume(struct cs4281_state *s)
-{
-	int i;
-	unsigned temp1;
-	u32 u32CLKCR1;
-	struct cs4281_pm *pm = &s->pm;
-	CS_DBGOUT(CS_PM | CS_FUNCTION, 4, 
-		printk( "cs4281: cs4281_resume()+ flags=%d\n",
-			(unsigned)s->pm.flags));
-	if(!(s->pm.flags & CS4281_PM_SUSPENDED))
-	{
-		CS_DBGOUT(CS_PM | CS_ERROR, 2, 
-			printk("cs4281: cs4281_resume() unable to resume, not SUSPENDED\n"));
-		return 1;
-	}
-	s->pm.flags &= ~CS4281_PM_SUSPENDED;
-	s->pm.flags |= CS4281_PM_RESUMING;
-
-//
-// Gershwin CLKRUN - Set CKRA
-//
-	u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
-	writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
-
-	//
-	// set the power state.
-	//
-	//old PokeBA0(BA0_PMCS, 0);
-
-	//
-	// Program the clock circuit and serial ports.
-	//
-	temp1 = cs4281_hw_init(s);
-	if (temp1) {
-		CS_DBGOUT(CS_ERROR | CS_INIT, 1,
-		    printk(KERN_ERR
-			"cs4281: resume cs4281_hw_init() error.\n"));
-		return -1;
-	}
-
-	//
-	// restore the Power state
-	//
-	writel(pm->u32SSPMValue, s->pBA0 + BA0_SSPM);
-
-	//
-	// Set post SRC mix setting (FM or ALT48K)
-	//
-	writel(pm->u32SSPM_BITS, s->pBA0 + BA0_SSPM);
-
-	//
-	// Loop through all of the PipeLines 
-	//
-	for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
-        {
-		if(s->pl[i].flags & CS4281_PIPELINE_VALID)
-		{
-		//
-		// Ask the DMAengines and FIFOs to Resume.
-		//
-			cs4281_ResumeDMAengine(s,&s->pl[i]);
-			cs4281_ResumeFIFO(s,&s->pl[i]);
-		}
-	}
-	//
-	// We need to restore the contents of the Midi Control Register.
-	//
-	writel(pm->u32MIDCR_Save, s->pBA0 + BA0_MIDCR);
-
-	cs4281_ac97_resume(s);
-	//
-	// Restore the PCM Playback Left and Right Volume Control.
-	//
-	writel(pm->u32PPLVCvalue, s->pBA0 + BA0_PPLVC);
-	writel(pm->u32PPRVCvalue, s->pBA0 + BA0_PPRVC);
-
-	//
-	// Restore the FM Synthesis Left and Right Volume Control.
-	//
-	writel(pm->u32FMLVCvalue, s->pBA0 + BA0_FMLVC);
-	writel(pm->u32FMRVCvalue, s->pBA0 + BA0_FMRVC);
-
-	//
-	// Restore the JSCTL value.
-	//
-	writel(pm->u32JSCTLvalue, s->pBA0 + BA0_JSCTL);
-
-	//
-	// Restore the GPIOR register value.
-	//
-	writel(pm->u32GPIORvalue, s->pBA0 + BA0_GPIOR);
-
-	//
-	// Restore Sound System Control Register
-	//
-	writel(pm->u32SSCR, s->pBA0 + BA0_SSCR);
-
-	//
-	// Restore SRC Slot Assignment register
-	//
-	writel(pm->u32SRCSA, s->pBA0 + BA0_SRCSA);
-
-	//
-	// Restore sample rate
-	//
-	writel(pm->u32DacASR, s->pBA0 + BA0_PASR);
-	writel(pm->u32AdcASR, s->pBA0 + BA0_CASR);
-	writel(pm->u32DacSR, s->pBA0 + BA0_DACSR);
-	writel(pm->u32AdcSR, s->pBA0 + BA0_ADCSR);
-
-	// 
-	// Restore CFL1/2 registers we saved to compensate for OEM bugs.
-	//
-	//	PokeBA0(BA0_CFLR, ulConfig);
-
-	//
-	// Gershwin CLKRUN - Clear CKRA
-	//
-	writel(pm->u32CLKCR1_SAVE, s->pBA0 + BA0_CLKCR1);
-
-	//
-	// Enable interrupts on the part.
-	//
-	writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
-
-#ifdef CSDEBUG
-	printpm(s);
-	printpipelines(s);
-#endif
-/*
-* change the state, restore the current hwptrs, then stop the dac/adc
-*/
-	s->pm.flags |= CS4281_PM_IDLE;
-	s->pm.flags &= ~(CS4281_PM_SUSPENDING | CS4281_PM_SUSPENDED 
-			| CS4281_PM_RESUMING | CS4281_PM_RESUMED);
-
-	writel(s->pm.u32hwptr_playback, s->pBA0 + BA0_DCA0);
-	writel(s->pm.u32hwptr_capture, s->pBA0 + BA0_DCA1);
-	start_dac(s);
-	start_adc(s);
-
-	CS_DBGOUT(CS_PM | CS_FUNCTION, 9, printk("cs4281: cs4281_resume()- flags=%d\n",
-		(unsigned)s->pm.flags));
-	return 0;
-}
-
-#endif
-
-//******************************************************************************
-// "cs4281_play_rate()" --
-//******************************************************************************
-static void cs4281_play_rate(struct cs4281_state *card, u32 playrate)
-{
-	u32 DACSRvalue = 1;
-
-	// Based on the sample rate, program the DACSR register.
-	if (playrate == 8000)
-		DACSRvalue = 5;
-	if (playrate == 11025)
-		DACSRvalue = 4;
-	else if (playrate == 22050)
-		DACSRvalue = 2;
-	else if (playrate == 44100)
-		DACSRvalue = 1;
-	else if ((playrate <= 48000) && (playrate >= 6023))
-		DACSRvalue = 24576000 / (playrate * 16);
-	else if (playrate < 6023)
-		// Not allowed by open.
-		return;
-	else if (playrate > 48000)
-		// Not allowed by open.
-		return;
-	CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO
-		"cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",
-			DACSRvalue, playrate));
-	//  Write the 'sample rate select code'
-	//  to the 'DAC Sample Rate' register.
-	writel(DACSRvalue, card->pBA0 + BA0_DACSR);	// (744h)
-}
-
-//******************************************************************************
-// "cs4281_record_rate()" -- Initialize the record sample rate converter.
-//******************************************************************************
-static void cs4281_record_rate(struct cs4281_state *card, u32 outrate)
-{
-	u32 ADCSRvalue = 1;
-
-	//
-	// Based on the sample rate, program the ADCSR register
-	//
-	if (outrate == 8000)
-		ADCSRvalue = 5;
-	if (outrate == 11025)
-		ADCSRvalue = 4;
-	else if (outrate == 22050)
-		ADCSRvalue = 2;
-	else if (outrate == 44100)
-		ADCSRvalue = 1;
-	else if ((outrate <= 48000) && (outrate >= 6023))
-		ADCSRvalue = 24576000 / (outrate * 16);
-	else if (outrate < 6023) {
-		// Not allowed by open.
-		return;
-	} else if (outrate > 48000) {
-		// Not allowed by open.
-		return;
-	}
-	CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO
-		"cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",
-			ADCSRvalue, outrate));
-	//  Write the 'sample rate select code
-	//  to the 'ADC Sample Rate' register.
-	writel(ADCSRvalue, card->pBA0 + BA0_ADCSR);	// (748h)
-}
-
-
-
-static void stop_dac(struct cs4281_state *s)
-{
-	unsigned long flags;
-	unsigned temp1;
-
-	CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n"));
-	spin_lock_irqsave(&s->lock, flags);
-	s->ena &= ~FMODE_WRITE;
-	temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK;
-	writel(temp1, s->pBA0 + BA0_DCR0);
-
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void start_dac(struct cs4281_state *s)
-{
-	unsigned long flags;
-	unsigned temp1;
-
-	CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: start_dac()+\n"));
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped ||
-					(s->dma_dac.count > 0
-	    				&& s->dma_dac.ready))
-#ifndef NOT_CS4281_PM
-	&& (s->pm.flags & CS4281_PM_IDLE))
-#else
-)
-#endif
- {
-		s->ena |= FMODE_WRITE;
-		temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK;	// Clear DMA0 channel mask.
-		writel(temp1, s->pBA0 + BA0_DCR0);	// Start DMA'ing.
-		writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);	// Enable interrupts.              
-
-		writel(7, s->pBA0 + BA0_PPRVC);
-		writel(7, s->pBA0 + BA0_PPLVC);
-		CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO
-			"cs4281: start_dac(): writel 0x%x start dma\n", temp1));
-
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	CS_DBGOUT(CS_FUNCTION, 3,
-		  printk(KERN_INFO "cs4281: start_dac()-\n"));
-}
-
-
-static void stop_adc(struct cs4281_state *s)
-{
-	unsigned long flags;
-	unsigned temp1;
-
-	CS_DBGOUT(CS_FUNCTION, 3,
-		  printk(KERN_INFO "cs4281: stop_adc()+\n"));
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->ena &= ~FMODE_READ;
-
-	if (s->conversion == 1) {
-		s->conversion = 0;
-		s->prop_adc.fmt = s->prop_adc.fmt_original;
-	}
-	temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK;
-	writel(temp1, s->pBA0 + BA0_DCR1);
-	spin_unlock_irqrestore(&s->lock, flags);
-	CS_DBGOUT(CS_FUNCTION, 3,
-		  printk(KERN_INFO "cs4281: stop_adc()-\n"));
-}
-
-
-static void start_adc(struct cs4281_state *s)
-{
-	unsigned long flags;
-	unsigned temp1;
-
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: start_adc()+\n"));
-
-	if (!(s->ena & FMODE_READ) &&
-	    (s->dma_adc.mapped || s->dma_adc.count <=
-	     (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize))
-	    && s->dma_adc.ready
-#ifndef NOT_CS4281_PM
-	&& (s->pm.flags & CS4281_PM_IDLE))
-#else
-) 
-#endif
-	{
-		if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) {
-			// 
-			// now only use 16 bit capture, due to truncation issue
-			// in the chip, noticable distortion occurs.
-			// allocate buffer and then convert from 16 bit to 
-			// 8 bit for the user buffer.
-			//
-			s->prop_adc.fmt_original = s->prop_adc.fmt;
-			if (s->prop_adc.fmt & AFMT_S8) {
-				s->prop_adc.fmt &= ~AFMT_S8;
-				s->prop_adc.fmt |= AFMT_S16_LE;
-			}
-			if (s->prop_adc.fmt & AFMT_U8) {
-				s->prop_adc.fmt &= ~AFMT_U8;
-				s->prop_adc.fmt |= AFMT_U16_LE;
-			}
-			//
-			// prog_dmabuf_adc performs a stop_adc() but that is
-			// ok since we really haven't started the DMA yet.
-			//
-			prog_codec(s, CS_TYPE_ADC);
-
-			if (prog_dmabuf_adc(s) != 0) {
-				CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
-					 "cs4281: start_adc(): error in prog_dmabuf_adc\n"));
-			}
-			s->conversion = 1;
-		}
-		spin_lock_irqsave(&s->lock, flags);
-		s->ena |= FMODE_READ;
-		temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK;	// Clear DMA1 channel mask bit.
-		writel(temp1, s->pBA0 + BA0_DCR1);	// Start recording
-		writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);	// Enable interrupts.
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO
-			 "cs4281: start_adc(): writel 0x%x \n", temp1));
-	}
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: start_adc()-\n"));
-
-}
-
-
-// --------------------------------------------------------------------- 
-
-#define DMABUF_MINORDER 1	// ==> min buffer size = 8K.
-
-
-static void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db)
-{
-	struct page *map, *mapend;
-
-	if (db->rawbuf) {
-		// Undo prog_dmabuf()'s marking the pages as reserved 
-		mapend =
-		    virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -
-				 1);
-		for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
-			ClearPageReserved(map);
-		free_dmabuf(s, db);
-	}
-	if (s->tmpbuff && (db->type == CS_TYPE_ADC)) {
-		// Undo prog_dmabuf()'s marking the pages as reserved 
-		mapend =
-		    virt_to_page(s->tmpbuff +
-				 (PAGE_SIZE << s->buforder_tmpbuff) - 1);
-		for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
-			ClearPageReserved(map);
-		free_dmabuf2(s, db);
-	}
-	s->tmpbuff = NULL;
-	db->rawbuf = NULL;
-	db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
-{
-	int order;
-	unsigned bytespersec, temp1;
-	unsigned bufs, sample_shift = 0;
-	struct page *map, *mapend;
-	unsigned long df;
-
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: prog_dmabuf()+\n"));
-	db->hwptr = db->swptr = db->total_bytes = db->count = db->error =
-	    db->endcleared = db->blocks = db->wakeup = db->underrun = 0;
-/*
-* check for order within limits, but do not overwrite value, check
-* later for a fractional defaultorder (i.e. 100+).
-*/
-	if((defaultorder > 0) && (defaultorder < 12))
-		df = defaultorder;
-	else
-		df = 1;	
-
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-		for (order = df; order >= DMABUF_MINORDER; order--)
-			if ( (db->rawbuf = (void *) pci_alloc_consistent(
-				s->pcidev, PAGE_SIZE << order, &db-> dmaaddr)))
-				    break;
-		if (!db->rawbuf) {
-			CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
-				"cs4281: prog_dmabuf(): unable to allocate rawbuf\n"));
-			return -ENOMEM;
-		}
-		db->buforder = order;
-		// Now mark the pages as reserved; otherwise the 
-		// remap_pfn_range() in cs4281_mmap doesn't work.
-		// 1. get index to last page in mem_map array for rawbuf.
-		mapend = virt_to_page(db->rawbuf + 
-			(PAGE_SIZE << db->buforder) - 1);
-
-		// 2. mark each physical page in range as 'reserved'.
-		for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
-			SetPageReserved(map);
-	}
-	if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) {
-		for (order = df; order >= DMABUF_MINORDER;
-		     order--)
-			if ( (s->tmpbuff = (void *) pci_alloc_consistent(
-					s->pcidev, PAGE_SIZE << order, 
-					&s->dmaaddr_tmpbuff)))
-				    break;
-		if (!s->tmpbuff) {
-			CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
-				"cs4281: prog_dmabuf(): unable to allocate tmpbuff\n"));
-			return -ENOMEM;
-		}
-		s->buforder_tmpbuff = order;
-		// Now mark the pages as reserved; otherwise the 
-		// remap_pfn_range() in cs4281_mmap doesn't work.
-		// 1. get index to last page in mem_map array for rawbuf.
-		mapend = virt_to_page(s->tmpbuff + 
-				(PAGE_SIZE << s->buforder_tmpbuff) - 1);
-
-		// 2. mark each physical page in range as 'reserved'.
-		for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
-			SetPageReserved(map);
-	}
-	if (db->type == CS_TYPE_DAC) {
-		if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
-			sample_shift++;
-		if (s->prop_dac.channels > 1)
-			sample_shift++;
-		bytespersec = s->prop_dac.rate << sample_shift;
-	} else			// CS_TYPE_ADC
-	{
-		if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
-			sample_shift++;
-		if (s->prop_adc.channels > 1)
-			sample_shift++;
-		bytespersec = s->prop_adc.rate << sample_shift;
-	}
-	bufs = PAGE_SIZE << db->buforder;
-
-/*
-* added fractional "defaultorder" inputs. if >100 then use 
-* defaultorder-100 as power of 2 for the buffer size. example:
-* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
-*/
-	if(defaultorder >= 100)
-	{
-		bufs = 1 << (defaultorder-100);
-	}
-
-#define INTERRUPT_RATE_MS       100	// Interrupt rate in milliseconds.
-	db->numfrag = 2;
-/* 
-* Nominal frag size(bytes/interrupt)
-*/
-	temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS);
-	db->fragshift = 8;	// Min 256 bytes.
-	while (1 << db->fragshift < temp1)	// Calc power of 2 frag size.
-		db->fragshift += 1;
-	db->fragsize = 1 << db->fragshift;
-	db->dmasize = db->fragsize * 2;
-	db->fragsamples = db->fragsize >> sample_shift;	// # samples/fragment.
-
-// If the calculated size is larger than the allocated
-//  buffer, divide the allocated buffer into 2 fragments.
-	if (db->dmasize > bufs) {
-
-		db->numfrag = 2;	// Two fragments.
-		db->fragsize = bufs >> 1;	// Each 1/2 the alloc'ed buffer.
-		db->fragsamples = db->fragsize >> sample_shift;	// # samples/fragment.
-		db->dmasize = bufs;	// Use all the alloc'ed buffer.
-
-		db->fragshift = 0;	// Calculate 'fragshift'.
-		temp1 = db->fragsize;	// update_ptr() uses it 
-		while ((temp1 >>= 1) > 1)	// to calc 'total-bytes'
-			db->fragshift += 1;	// returned in DSP_GETI/OPTR. 
-	}
-	CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO
-		"cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n",
-			db->numfrag, db->fragsize, db->fragsamples, 
-			db->fragshift, bufs, 
-			(db->type == CS_TYPE_DAC) ? s->prop_dac.fmt : 
-				s->prop_adc.fmt, 
-			(db->type == CS_TYPE_DAC) ? s->prop_dac.channels : 
-				s->prop_adc.channels));
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: prog_dmabuf()-\n"));
-	return 0;
-}
-
-
-static int prog_dmabuf_adc(struct cs4281_state *s)
-{
-	unsigned long va;
-	unsigned count;
-	int c;
-	stop_adc(s);
-	s->dma_adc.type = CS_TYPE_ADC;
-	if ((c = prog_dmabuf(s, &s->dma_adc)))
-		return c;
-
-	if (s->dma_adc.rawbuf) {
-		memset(s->dma_adc.rawbuf,
-		       (s->prop_adc.
-			fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
-		       s->dma_adc.dmasize);
-	}
-	if (s->tmpbuff) {
-		memset(s->tmpbuff,
-		       (s->prop_adc.
-			fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
-		       PAGE_SIZE << s->buforder_tmpbuff);
-	}
-
-	va = virt_to_bus(s->dma_adc.rawbuf);
-
-	count = s->dma_adc.dmasize;
-
-	if (s->prop_adc.
-	    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
-		    count /= 2;	// 16-bit.
-
-	if (s->prop_adc.channels > 1)
-		count /= 2;	// Assume stereo.
-
-	CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO
-		"cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n",
-			count, (unsigned) va));
-
-	writel(va, s->pBA0 + BA0_DBA1);	// Set buffer start address.
-	writel(count - 1, s->pBA0 + BA0_DBC1);	// Set count. 
-	s->dma_adc.ready = 1;
-	return 0;
-}
-
-
-static int prog_dmabuf_dac(struct cs4281_state *s)
-{
-	unsigned long va;
-	unsigned count;
-	int c;
-	stop_dac(s);
-	s->dma_dac.type = CS_TYPE_DAC;
-	if ((c = prog_dmabuf(s, &s->dma_dac)))
-		return c;
-	memset(s->dma_dac.rawbuf,
-	       (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
-	       s->dma_dac.dmasize);
-
-	va = virt_to_bus(s->dma_dac.rawbuf);
-
-	count = s->dma_dac.dmasize;
-	if (s->prop_dac.
-	    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
-		    count /= 2;	// 16-bit.
-
-	if (s->prop_dac.channels > 1)
-		count /= 2;	// Assume stereo.
-
-	writel(va, s->pBA0 + BA0_DBA0);	// Set buffer start address.
-	writel(count - 1, s->pBA0 + BA0_DBC0);	// Set count.             
-
-	CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO
-		"cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n",
-			count, (unsigned) va));
-
-	s->dma_dac.ready = 1;
-	return 0;
-}
-
-
-static void clear_advance(void *buf, unsigned bsize, unsigned bptr,
-			  unsigned len, unsigned char c)
-{
-	if (bptr + len > bsize) {
-		unsigned x = bsize - bptr;
-		memset(((char *) buf) + bptr, c, x);
-		bptr = 0;
-		len -= x;
-	}
-	CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
-		"cs4281: clear_advance(): memset %d at %p for %d size \n",
-			(unsigned)c, ((char *) buf) + bptr, len));
-	memset(((char *) buf) + bptr, c, len);
-}
-
-
-
-// call with spinlock held! 
-static void cs4281_update_ptr(struct cs4281_state *s, int intflag)
-{
-	int diff;
-	unsigned hwptr, va;
-
-	// update ADC pointer 
-	if (s->ena & FMODE_READ) {
-		hwptr = readl(s->pBA0 + BA0_DCA1);	// Read capture DMA address.
-		va = virt_to_bus(s->dma_adc.rawbuf);
-		hwptr -= (unsigned) va;
-		diff =
-		    (s->dma_adc.dmasize + hwptr -
-		     s->dma_adc.hwptr) % s->dma_adc.dmasize;
-		s->dma_adc.hwptr = hwptr;
-		s->dma_adc.total_bytes += diff;
-		s->dma_adc.count += diff;
-		if (s->dma_adc.count > s->dma_adc.dmasize)
-			s->dma_adc.count = s->dma_adc.dmasize;
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >=
-			    (signed) s->dma_adc.fragsize) wake_up(&s->
-								  dma_adc.
-								  wait);
-		} else {
-			if (s->dma_adc.count > 0)
-				wake_up(&s->dma_adc.wait);
-		}
-		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
-			"cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
-				s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count));
-	}
-	// update DAC pointer 
-	//
-	// check for end of buffer, means that we are going to wait for another interrupt
-	// to allow silence to fill the fifos on the part, to keep pops down to a minimum.
-	//
-	if (s->ena & FMODE_WRITE) {
-		hwptr = readl(s->pBA0 + BA0_DCA0);	// Read play DMA address.
-		va = virt_to_bus(s->dma_dac.rawbuf);
-		hwptr -= (unsigned) va;
-		diff = (s->dma_dac.dmasize + hwptr -
-		     s->dma_dac.hwptr) % s->dma_dac.dmasize;
-		s->dma_dac.hwptr = hwptr;
-		s->dma_dac.total_bytes += diff;
-		if (s->dma_dac.mapped) {
-			s->dma_dac.count += diff;
-			if (s->dma_dac.count >= s->dma_dac.fragsize) {
-				s->dma_dac.wakeup = 1;
-				wake_up(&s->dma_dac.wait);
-				if (s->dma_dac.count > s->dma_dac.dmasize)
-					s->dma_dac.count &=
-					    s->dma_dac.dmasize - 1;
-			}
-		} else {
-			s->dma_dac.count -= diff;
-			if (s->dma_dac.count <= 0) {
-				//
-				// fill with silence, and do not shut down the DAC.
-				// Continue to play silence until the _release.
-				//
-				CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO
-					"cs4281: cs4281_update_ptr(): memset %d at %p for %d size \n",
-						(unsigned)(s->prop_dac.fmt & 
-						(AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, 
-						s->dma_dac.rawbuf, s->dma_dac.dmasize));
-				memset(s->dma_dac.rawbuf,
-				       (s->prop_dac.
-					fmt & (AFMT_U8 | AFMT_U16_LE)) ?
-				       0x80 : 0, s->dma_dac.dmasize);
-				if (s->dma_dac.count < 0) {
-					s->dma_dac.underrun = 1;
-					s->dma_dac.count = 0;
-					CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO
-					 "cs4281: cs4281_update_ptr(): underrun\n"));
-				}
-			} else if (s->dma_dac.count <=
-				   (signed) s->dma_dac.fragsize
-				   && !s->dma_dac.endcleared) {
-				clear_advance(s->dma_dac.rawbuf,
-					      s->dma_dac.dmasize,
-					      s->dma_dac.swptr,
-					      s->dma_dac.fragsize,
-					      (s->prop_dac.
-					       fmt & (AFMT_U8 |
-						      AFMT_U16_LE)) ? 0x80
-					      : 0);
-				s->dma_dac.endcleared = 1;
-			}
-			if ( (s->dma_dac.count <= (signed) s->dma_dac.dmasize/2) ||
-				intflag)
-			{
-				wake_up(&s->dma_dac.wait);
-			}
-		}
-		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
-			"cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
-				s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count));
-	}
-}
-
-
-// --------------------------------------------------------------------- 
-
-static void prog_codec(struct cs4281_state *s, unsigned type)
-{
-	unsigned long flags;
-	unsigned temp1, format;
-
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: prog_codec()+ \n"));
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (type == CS_TYPE_ADC) {
-		temp1 = readl(s->pBA0 + BA0_DCR1);
-		writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1);	// Stop capture DMA, if active.
-
-		// program sampling rates  
-		// Note, for CS4281, capture & play rates can be set independently.
-		cs4281_record_rate(s, s->prop_adc.rate);
-
-		// program ADC parameters 
-		format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;
-		if (s->prop_adc.
-		    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) {	// 16-bit
-			if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE))	// Big-endian?
-				format |= DMRn_BEND;
-			if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE))
-				format |= DMRn_USIGN;	// Unsigned.      
-		} else
-			format |= DMRn_SIZE8 | DMRn_USIGN;	// 8-bit, unsigned
-		if (s->prop_adc.channels < 2)
-			format |= DMRn_MONO;
-
-		writel(format, s->pBA0 + BA0_DMR1);
-
-		CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
-			"cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n",
-				(format & DMRn_SIZE8) ? "8" : "16",
-				(format & DMRn_USIGN) ?  "Unsigned" : "Signed", 
-				(format & DMRn_MONO) ? "Mono" : "Stereo", 
-				s->prop_adc.rate, format));
-
-		s->ena &= ~FMODE_READ;	// not capturing data yet
-	}
-
-
-	if (type == CS_TYPE_DAC) {
-		temp1 = readl(s->pBA0 + BA0_DCR0);
-		writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0);	// Stop play DMA, if active.
-
-		// program sampling rates  
-		// Note, for CS4281, capture & play rates can be set independently.
-		cs4281_play_rate(s, s->prop_dac.rate);
-
-		// program DAC parameters 
-		format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;
-		if (s->prop_dac.
-		    fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) {	// 16-bit
-			if (s->prop_dac.fmt & (AFMT_S16_BE | AFMT_U16_BE))
-				format |= DMRn_BEND;	// Big Endian.
-			if (s->prop_dac.fmt & (AFMT_U16_LE | AFMT_U16_BE))
-				format |= DMRn_USIGN;	// Unsigned.      
-		} else
-			format |= DMRn_SIZE8 | DMRn_USIGN;	// 8-bit, unsigned
-
-		if (s->prop_dac.channels < 2)
-			format |= DMRn_MONO;
-
-		writel(format, s->pBA0 + BA0_DMR0);
-
-
-		CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
-			"cs4281: prog_codec(): dac %s %s %s rate=%d DMR0 format=0x%.8x\n",
-				(format & DMRn_SIZE8) ? "8" : "16",
-				(format & DMRn_USIGN) ?  "Unsigned" : "Signed",
-				(format & DMRn_MONO) ? "Mono" : "Stereo", 
-				s->prop_dac.rate, format));
-
-		s->ena &= ~FMODE_WRITE;	// not capturing data yet
-
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: prog_codec()- \n"));
-}
-
-
-static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,
-		       unsigned long arg)
-{
-	// Index to mixer_src[] is value of AC97 Input Mux Select Reg.
-	// Value of array member is recording source Device ID Mask.
-	static const unsigned int mixer_src[8] = {
-		SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1,
-		SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0
-	};
-	void __user *argp = (void __user *)arg;
-
-	// Index of mixtable1[] member is Device ID 
-	// and must be <= SOUND_MIXER_NRDEVICES.
-	// Value of array member is index into s->mix.vol[]
-	static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
-		[SOUND_MIXER_PCM] = 1,	// voice 
-		[SOUND_MIXER_LINE1] = 2,	// AUX
-		[SOUND_MIXER_CD] = 3,	// CD 
-		[SOUND_MIXER_LINE] = 4,	// Line 
-		[SOUND_MIXER_SYNTH] = 5,	// FM
-		[SOUND_MIXER_MIC] = 6,	// Mic 
-		[SOUND_MIXER_SPEAKER] = 7,	// Speaker 
-		[SOUND_MIXER_RECLEV] = 8,	// Recording level 
-		[SOUND_MIXER_VOLUME] = 9	// Master Volume 
-	};
-
-
-	static const unsigned mixreg[] = {
-		BA0_AC97_PCM_OUT_VOLUME,
-		BA0_AC97_AUX_VOLUME,
-		BA0_AC97_CD_VOLUME,
-		BA0_AC97_LINE_IN_VOLUME
-	};
-	unsigned char l, r, rl, rr, vidx;
-	unsigned char attentbl[11] =
-	    { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 };
-	unsigned temp1;
-	int i, val;
-
-	VALIDATE_STATE(s);
-	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
-		 "cs4281: mixer_ioctl(): s=%p cmd=0x%.8x\n", s, cmd));
-#if CSDEBUG
-	cs_printioctl(cmd);
-#endif
-#if CSDEBUG_INTERFACE
-
-	if ((cmd == SOUND_MIXER_CS_GETDBGMASK) ||
-	    (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
-	    (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
-	    (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
-	    (cmd == SOUND_MIXER_CS_APM))
-	{
-		switch (cmd) {
-
-		case SOUND_MIXER_CS_GETDBGMASK:
-			return put_user(cs_debugmask,
-					(unsigned long __user *) argp);
-
-		case SOUND_MIXER_CS_GETDBGLEVEL:
-			return put_user(cs_debuglevel,
-					(unsigned long __user *) argp);
-
-		case SOUND_MIXER_CS_SETDBGMASK:
-			if (get_user(val, (unsigned long __user *) argp))
-				return -EFAULT;
-			cs_debugmask = val;
-			return 0;
-
-		case SOUND_MIXER_CS_SETDBGLEVEL:
-			if (get_user(val, (unsigned long __user *) argp))
-				return -EFAULT;
-			cs_debuglevel = val;
-			return 0;
-#ifndef NOT_CS4281_PM
-		case SOUND_MIXER_CS_APM:
-			if (get_user(val, (unsigned long __user *) argp))
-				return -EFAULT;
-			if(val == CS_IOCTL_CMD_SUSPEND)
-				cs4281_suspend(s);
-			else if(val == CS_IOCTL_CMD_RESUME)
-				cs4281_resume(s);
-			else
-			{
-				CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
-				    "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n",
-					val));
-			}
-			return 0;
-#endif
-		default:
-			CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
-				"cs4281: mixer_ioctl(): ERROR unknown debug cmd\n"));
-			return 0;
-		}
-	}
-#endif
-
-	if (cmd == SOUND_MIXER_PRIVATE1) {
-		// enable/disable/query mixer preamp 
-		if (get_user(val, (int __user *) argp))
-			return -EFAULT;
-		if (val != -1) {
-			cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
-			temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf);
-			cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
-		}
-		cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
-		val = (temp1 & 0x40) ? 1 : 0;
-		return put_user(val, (int __user *) argp);
-	}
-	if (cmd == SOUND_MIXER_PRIVATE2) {
-		// enable/disable/query spatializer 
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		if (val != -1) {
-			temp1 = (val & 0x3f) >> 2;
-			cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1);
-			cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE,
-					 &temp1);
-			cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,
-					  temp1 | 0x2000);
-		}
-		cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1);
-		return put_user((temp1 << 2) | 3, (int __user *)argp);
-	}
-	if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		strlcpy(info.id, "CS4281", sizeof(info.id));
-		strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
-		info.modify_counter = s->mix.modcnt;
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		strlcpy(info.id, "CS4281", sizeof(info.id));
-		strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, (int __user *) argp);
-
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-		return -EINVAL;
-
-	// If ioctl has only the SIOC_READ bit(bit 31)
-	// on, process the only-read commands. 
-	if (_SIOC_DIR(cmd) == _SIOC_READ) {
-		switch (_IOC_NR(cmd)) {
-		case SOUND_MIXER_RECSRC:	// Arg contains a bit for each recording source 
-			cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1);
-			return put_user(mixer_src[temp1&7], (int __user *)argp);
-
-		case SOUND_MIXER_DEVMASK:	// Arg contains a bit for each supported device 
-			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
-					SOUND_MASK_CD | SOUND_MASK_LINE |
-					SOUND_MASK_LINE1 | SOUND_MASK_MIC |
-					SOUND_MASK_VOLUME |
-					SOUND_MASK_RECLEV |
-					SOUND_MASK_SPEAKER, (int __user *)argp);
-
-		case SOUND_MIXER_RECMASK:	// Arg contains a bit for each supported recording source 
-			return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC |
-					SOUND_MASK_CD | SOUND_MASK_VOLUME |
-					SOUND_MASK_LINE1, (int __user *) argp);
-
-		case SOUND_MIXER_STEREODEVS:	// Mixer channels supporting stereo 
-			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
-					SOUND_MASK_CD | SOUND_MASK_LINE |
-					SOUND_MASK_LINE1 | SOUND_MASK_MIC |
-					SOUND_MASK_VOLUME |
-					SOUND_MASK_RECLEV, (int __user *)argp);
-
-		case SOUND_MIXER_CAPS:
-			return put_user(SOUND_CAP_EXCL_INPUT, (int __user *)argp);
-
-		default:
-			i = _IOC_NR(cmd);
-			if (i >= SOUND_MIXER_NRDEVICES
-			    || !(vidx = mixtable1[i]))
-				return -EINVAL;
-			return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
-		}
-	}
-	// If ioctl doesn't have both the SIOC_READ and 
-	// the SIOC_WRITE bit set, return invalid.
-	if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE))
-		return -EINVAL;
-
-	// Increment the count of volume writes.
-	s->mix.modcnt++;
-
-	// Isolate the command; it must be a write.
-	switch (_IOC_NR(cmd)) {
-
-	case SOUND_MIXER_RECSRC:	// Arg contains a bit for each recording source 
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		i = hweight32(val);	// i = # bits on in val.
-		if (i != 1)	// One & only 1 bit must be on.
-			return 0;
-		for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) {
-			if (val == mixer_src[i]) {
-				temp1 = (i << 8) | i;
-				cs4281_write_ac97(s,
-						  BA0_AC97_RECORD_SELECT,
-						  temp1);
-				return 0;
-			}
-		}
-		return 0;
-
-	case SOUND_MIXER_VOLUME:
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;	// Max soundcard.h vol is 100.
-		if (l < 6) {
-			rl = 63;
-			l = 0;
-		} else
-			rl = attentbl[(10 * l) / 100];	// Convert 0-100 vol to 63-0 atten.
-
-		r = (val >> 8) & 0xff;
-		if (r > 100)
-			r = 100;	// Max right volume is 100, too
-		if (r < 6) {
-			rr = 63;
-			r = 0;
-		} else
-			rr = attentbl[(10 * r) / 100];	// Convert volume to attenuation.
-
-		if ((rl > 60) && (rr > 60))	// If both l & r are 'low',          
-			temp1 = 0x8000;	//  turn on the mute bit.
-		else
-			temp1 = 0;
-
-		temp1 |= (rl << 8) | rr;
-
-		cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1);
-		cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		s->mix.vol[8] = ((unsigned int) r << 8) | l;
-#else
-		s->mix.vol[8] = val;
-#endif
-		return put_user(s->mix.vol[8], (int __user *)argp);
-
-	case SOUND_MIXER_SPEAKER:
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		if (l < 3) {
-			rl = 0;
-			l = 0;
-		} else {
-			rl = (l * 2 - 5) / 13;	// Convert 0-100 range to 0-15.
-			l = (rl * 13 + 5) / 2;
-		}
-
-		if (rl < 3) {
-			temp1 = 0x8000;
-			rl = 0;
-		} else
-			temp1 = 0;
-		rl = 15 - rl;	// Convert volume to attenuation.
-		temp1 |= rl << 1;
-		cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		s->mix.vol[6] = l << 8;
-#else
-		s->mix.vol[6] = val;
-#endif
-		return put_user(s->mix.vol[6], (int __user *)argp);
-
-	case SOUND_MIXER_RECLEV:
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		r = (val >> 8) & 0xff;
-		if (r > 100)
-			r = 100;
-		rl = (l * 2 - 5) / 13;	// Convert 0-100 scale to 0-15.
-		rr = (r * 2 - 5) / 13;
-		if (rl < 3 && rr < 3)
-			temp1 = 0x8000;
-		else
-			temp1 = 0;
-
-		temp1 = temp1 | (rl << 8) | rr;
-		cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		s->mix.vol[7] = ((unsigned int) r << 8) | l;
-#else
-		s->mix.vol[7] = val;
-#endif
-		return put_user(s->mix.vol[7], (int __user *)argp);
-
-	case SOUND_MIXER_MIC:
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		if (l < 1) {
-			l = 0;
-			rl = 0;
-		} else {
-			rl = ((unsigned) l * 5 - 4) / 16;	// Convert 0-100 range to 0-31.
-			l = (rl * 16 + 4) / 5;
-		}
-		cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
-		temp1 &= 0x40;	// Isolate 20db gain bit.
-		if (rl < 3) {
-			temp1 |= 0x8000;
-			rl = 0;
-		}
-		rl = 31 - rl;	// Convert volume to attenuation.
-		temp1 |= rl;
-		cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		s->mix.vol[5] = val << 8;
-#else
-		s->mix.vol[5] = val;
-#endif
-		return put_user(s->mix.vol[5], (int __user *)argp);
-
-
-	case SOUND_MIXER_SYNTH:
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		r = (val >> 8) & 0xff;
-		if (r > 100)
-			r = 100;
-		rl = (l * 2 - 11) / 3;	// Convert 0-100 range to 0-63.
-		rr = (r * 2 - 11) / 3;
-		if (rl < 3)	// If l is low, turn on
-			temp1 = 0x0080;	//  the mute bit.
-		else
-			temp1 = 0;
-
-		rl = 63 - rl;	// Convert vol to attenuation.
-		writel(temp1 | rl, s->pBA0 + BA0_FMLVC);
-		if (rr < 3)	//  If rr is low, turn on
-			temp1 = 0x0080;	//   the mute bit.
-		else
-			temp1 = 0;
-		rr = 63 - rr;	// Convert vol to attenuation.
-		writel(temp1 | rr, s->pBA0 + BA0_FMRVC);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		s->mix.vol[4] = (r << 8) | l;
-#else
-		s->mix.vol[4] = val;
-#endif
-		return put_user(s->mix.vol[4], (int __user *)argp);
-
-
-	default:
-		CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
-			"cs4281: mixer_ioctl(): default\n"));
-
-		i = _IOC_NR(cmd);
-		if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
-			return -EINVAL;
-		if (get_user(val, (int __user *)argp))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		if (l < 1) {
-			l = 0;
-			rl = 31;
-		} else
-			rl = (attentbl[(l * 10) / 100]) >> 1;
-
-		r = (val >> 8) & 0xff;
-		if (r > 100)
-			r = 100;
-		if (r < 1) {
-			r = 0;
-			rr = 31;
-		} else
-			rr = (attentbl[(r * 10) / 100]) >> 1;
-		if ((rl > 30) && (rr > 30))
-			temp1 = 0x8000;
-		else
-			temp1 = 0;
-		temp1 = temp1 | (rl << 8) | rr;
-		cs4281_write_ac97(s, mixreg[vidx - 1], temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l;
-#else
-		s->mix.vol[vidx - 1] = val;
-#endif
-#ifndef NOT_CS4281_PM
-		CS_DBGOUT(CS_PM, 9, printk(KERN_INFO 
-			"write ac97 mixreg[%d]=0x%x mix.vol[]=0x%x\n", 
-				vidx-1,temp1,s->mix.vol[vidx-1]));
-#endif
-		return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
-	}
-}
-
-
-// --------------------------------------------------------------------- 
-
-static int cs4281_open_mixdev(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct cs4281_state *s=NULL;
-	struct list_head *entry;
-
-	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
-		  printk(KERN_INFO "cs4281: cs4281_open_mixdev()+\n"));
-
-	list_for_each(entry, &cs4281_devs)
-	{
-		s = list_entry(entry, struct cs4281_state, list);
-		if(s->dev_mixer == minor)
-			break;
-	}
-	if (!s)
-	{
-		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
-			printk(KERN_INFO "cs4281: cs4281_open_mixdev()- -ENODEV\n"));
-		return -ENODEV;
-	}
-	VALIDATE_STATE(s);
-	file->private_data = s;
-
-	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
-		  printk(KERN_INFO "cs4281: cs4281_open_mixdev()- 0\n"));
-
-	return nonseekable_open(inode, file);
-}
-
-
-static int cs4281_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-
-	VALIDATE_STATE(s);
-	return 0;
-}
-
-
-static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file,
-			       unsigned int cmd, unsigned long arg)
-{
-	return mixer_ioctl((struct cs4281_state *) file->private_data, cmd,
-			   arg);
-}
-
-
-// ******************************************************************************************
-//   Mixer file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_mixer_fops = {
-	.owner	 = THIS_MODULE,
-	.llseek	 = no_llseek,
-	.ioctl	 = cs4281_ioctl_mixdev,
-	.open	 = cs4281_open_mixdev,
-	.release = cs4281_release_mixdev,
-};
-
-// --------------------------------------------------------------------- 
-
-
-static int drain_adc(struct cs4281_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count;
-	unsigned tmo;
-
-	if (s->dma_adc.mapped)
-		return 0;
-	add_wait_queue(&s->dma_adc.wait, &wait);
-	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_adc.count;
-		CS_DBGOUT(CS_FUNCTION, 2,
-			  printk(KERN_INFO "cs4281: drain_adc() %d\n", count));
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0) {
-			CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
-				 "cs4281: drain_adc() count<0\n"));
-			break;
-		}
-		if (signal_pending(current))
-			break;
-		if (nonblock) {
-			remove_wait_queue(&s->dma_adc.wait, &wait);
-			current->state = TASK_RUNNING;
-			return -EBUSY;
-		}
-		tmo =
-		    3 * HZ * (count +
-			      s->dma_adc.fragsize) / 2 / s->prop_adc.rate;
-		if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
-			tmo >>= 1;
-		if (s->prop_adc.channels > 1)
-			tmo >>= 1;
-		if (!schedule_timeout(tmo + 1))
-			printk(KERN_DEBUG "cs4281: dma timed out??\n");
-	}
-	remove_wait_queue(&s->dma_adc.wait, &wait);
-	current->state = TASK_RUNNING;
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-static int drain_dac(struct cs4281_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count;
-	unsigned tmo;
-
-	if (s->dma_dac.mapped)
-		return 0;
-	add_wait_queue(&s->dma_dac.wait, &wait);
-	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-			break;
-		if (nonblock) {
-			remove_wait_queue(&s->dma_dac.wait, &wait);
-			current->state = TASK_RUNNING;
-			return -EBUSY;
-		}
-		tmo =
-		    3 * HZ * (count +
-			      s->dma_dac.fragsize) / 2 / s->prop_dac.rate;
-		if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
-			tmo >>= 1;
-		if (s->prop_dac.channels > 1)
-			tmo >>= 1;
-		if (!schedule_timeout(tmo + 1))
-			printk(KERN_DEBUG "cs4281: dma timed out??\n");
-	}
-	remove_wait_queue(&s->dma_dac.wait, &wait);
-	current->state = TASK_RUNNING;
-	if (signal_pending(current))
-		return -ERESTARTSYS;
-	return 0;
-}
-
-//****************************************************************************
-//
-// CopySamples copies 16-bit stereo samples from the source to the
-// destination, possibly converting down to either 8-bit or mono or both.
-// count specifies the number of output bytes to write.
-//
-//  Arguments:
-//
-//  dst             - Pointer to a destination buffer.
-//  src             - Pointer to a source buffer
-//  count           - The number of bytes to copy into the destination buffer.
-//  iChannels       - Stereo - 2
-//                    Mono   - 1
-//  fmt             - AFMT_xxx (soundcard.h formats)
-//
-// NOTES: only call this routine for conversion to 8bit from 16bit
-//
-//****************************************************************************
-static void CopySamples(char *dst, char *src, int count, int iChannels,
-			unsigned fmt)
-{
-
-	unsigned short *psSrc;
-	long lAudioSample;
-
-	CS_DBGOUT(CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: CopySamples()+ "));
-	CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
-		 " dst=%p src=%p count=%d iChannels=%d fmt=0x%x\n",
-			 dst, src, (unsigned) count, (unsigned) iChannels, (unsigned) fmt));
-
-	// Gershwin does format conversion in hardware so normally
-	// we don't do any host based coversion. The data formatter
-	// truncates 16 bit data to 8 bit and that causes some hiss.
-	// We have already forced the HW to do 16 bit sampling and 
-	// 2 channel so that we can use software to round instead 
-	// of truncate
-
-	//
-	// See if the data should be output as 8-bit unsigned stereo.
-	// or if the data should be output at 8-bit unsigned mono.
-	//
-	if ( ((iChannels == 2) && (fmt & AFMT_U8)) ||
-		((iChannels == 1) && (fmt & AFMT_U8)) ) {
-		//
-		// Convert each 16-bit unsigned stereo sample to 8-bit unsigned 
-		// stereo using rounding.
-		//
-		psSrc = (unsigned short *) src;
-		count = count / 2;
-		while (count--) {
-			lAudioSample = (long) psSrc[count] + (long) 0x80;
-			if (lAudioSample > 0xffff) {
-				lAudioSample = 0xffff;
-			}
-			dst[count] = (char) (lAudioSample >> 8);
-		}
-	}
-	//
-	// check for 8-bit signed stereo.
-	//
-	else if ((iChannels == 2) && (fmt & AFMT_S8)) {
-		//
-		// Convert each 16-bit stereo sample to 8-bit stereo using rounding.
-		//
-		psSrc = (short *) src;
-		while (count--) {
-			lAudioSample =
-			    (((long) psSrc[0] + (long) psSrc[1]) / 2);
-			psSrc += 2;
-			*dst++ = (char) ((short) lAudioSample >> 8);
-		}
-	}
-	//
-	// Otherwise, the data should be output as 8-bit signed mono.
-	//
-	else if ((iChannels == 1) && (fmt & AFMT_S8)) {
-		//
-		// Convert each 16-bit signed mono sample to 8-bit signed mono 
-		// using rounding.
-		//
-		psSrc = (short *) src;
-		count = count / 2;
-		while (count--) {
-			lAudioSample =
-			    (((long) psSrc[0] + (long) psSrc[1]) / 2);
-			if (lAudioSample > 0x7fff) {
-				lAudioSample = 0x7fff;
-			}
-			psSrc += 2;
-			*dst++ = (char) ((short) lAudioSample >> 8);
-		}
-	}
-}
-
-//
-// cs_copy_to_user()
-// replacement for the standard copy_to_user, to allow for a conversion from
-// 16 bit to 8 bit if the record conversion is active.  the cs4281 has some
-// issues with 8 bit capture, so the driver always captures data in 16 bit
-// and then if the user requested 8 bit, converts from 16 to 8 bit.
-//
-static unsigned cs_copy_to_user(struct cs4281_state *s, void __user *dest,
-				unsigned *hwsrc, unsigned cnt,
-				unsigned *copied)
-{
-	void *src = hwsrc;	//default to the standard destination buffer addr
-
-	CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
-		"cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=%p\n",
-			s->prop_adc.fmt, s->prop_adc.fmt_original,
-			(unsigned) cnt, dest));
-
-	if (cnt > s->dma_adc.dmasize) {
-		cnt = s->dma_adc.dmasize;
-	}
-	if (!cnt) {
-		*copied = 0;
-		return 0;
-	}
-	if (s->conversion) {
-		if (!s->tmpbuff) {
-			*copied = cnt / 2;
-			return 0;
-		}
-		CopySamples(s->tmpbuff, (void *) hwsrc, cnt,
-			    (unsigned) s->prop_adc.channels,
-			    s->prop_adc.fmt_original);
-		src = s->tmpbuff;
-		cnt = cnt / 2;
-	}
-
-	if (copy_to_user(dest, src, cnt)) {
-		*copied = 0;
-		return -EFAULT;
-	}
-	*copied = cnt;
-	CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
-		"cs4281: cs_copy_to_user()- copied bytes is %d \n", cnt));
-	return 0;
-}
-
-// --------------------------------------------------------------------- 
-
-static ssize_t cs4281_read(struct file *file, char __user *buffer, size_t count,
-			   loff_t * ppos)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-	unsigned copied = 0;
-
-	CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
-		  printk(KERN_INFO "cs4281: cs4281_read()+ %Zu \n", count));
-
-	VALIDATE_STATE(s);
-	if (s->dma_adc.mapped)
-		return -ENXIO;
-	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-//
-// "count" is the amount of bytes to read (from app), is decremented each loop
-//      by the amount of bytes that have been returned to the user buffer.
-// "cnt" is the running total of each read from the buffer (changes each loop)
-// "buffer" points to the app's buffer
-// "ret" keeps a running total of the amount of bytes that have been copied
-//      to the user buffer.
-// "copied" is the total bytes copied into the user buffer for each loop.
-//
-	while (count > 0) {
-		CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
-			"_read() count>0 count=%Zu .count=%d .swptr=%d .hwptr=%d \n",
-				count, s->dma_adc.count,
-				s->dma_adc.swptr, s->dma_adc.hwptr));
-		spin_lock_irqsave(&s->lock, flags);
-
-		// get the current copy point of the sw buffer
-		swptr = s->dma_adc.swptr;
-
-		// cnt is the amount of unread bytes from the end of the 
-		// hw buffer to the current sw pointer
-		cnt = s->dma_adc.dmasize - swptr;
-
-		// dma_adc.count is the current total bytes that have not been read.
-		// if the amount of unread bytes from the current sw pointer to the
-		// end of the buffer is greater than the current total bytes that
-		// have not been read, then set the "cnt" (unread bytes) to the
-		// amount of unread bytes.  
-
-		if (s->dma_adc.count < cnt)
-			cnt = s->dma_adc.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		//
-		// if we are converting from 8/16 then we need to copy
-		// twice the number of 16 bit bytes then 8 bit bytes.
-		// 
-		if (s->conversion) {
-			if (cnt > (count * 2))
-				cnt = (count * 2);
-		} else {
-			if (cnt > count)
-				cnt = count;
-		}
-		//
-		// "cnt" NOW is the smaller of the amount that will be read,
-		// and the amount that is requested in this read (or partial).
-		// if there are no bytes in the buffer to read, then start the
-		// ADC and wait for the interrupt handler to wake us up.
-		//
-		if (cnt <= 0) {
-
-			// start up the dma engine and then continue back to the top of
-			// the loop when wake up occurs.
-			start_adc(s);
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->dma_adc.wait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
-			continue;
-		}
-		// there are bytes in the buffer to read.
-		// copy from the hw buffer over to the user buffer.
-		// user buffer is designated by "buffer"
-		// virtual address to copy from is rawbuf+swptr
-		// the "cnt" is the number of bytes to read.
-
-		CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
-			"_read() copy_to cnt=%d count=%Zu ", cnt, count));
-		CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
-			 " .dmasize=%d .count=%d buffer=%p ret=%Zd\n",
-				 s->dma_adc.dmasize, s->dma_adc.count, buffer, ret));
-
-		if (cs_copy_to_user
-		    (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied))
-			return ret ? ret : -EFAULT;
-		swptr = (swptr + cnt) % s->dma_adc.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_adc.swptr = swptr;
-		s->dma_adc.count -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= copied;
-		buffer += copied;
-		ret += copied;
-		start_adc(s);
-	}
-	CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
-		  printk(KERN_INFO "cs4281: cs4281_read()- %Zd\n", ret));
-	return ret;
-}
-
-
-static ssize_t cs4281_write(struct file *file, const char __user *buffer,
-			    size_t count, loff_t * ppos)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr, hwptr, busaddr;
-	int cnt;
-
-	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
-		  printk(KERN_INFO "cs4281: cs4281_write()+ count=%Zu\n",
-			 count));
-	VALIDATE_STATE(s);
-
-	if (s->dma_dac.mapped)
-		return -ENXIO;
-	if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	ret = 0;
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		if (s->dma_dac.count < 0) {
-			s->dma_dac.count = 0;
-			s->dma_dac.swptr = s->dma_dac.hwptr;
-		}
-		if (s->dma_dac.underrun) {
-			s->dma_dac.underrun = 0;
-			hwptr = readl(s->pBA0 + BA0_DCA0);
-			busaddr = virt_to_bus(s->dma_dac.rawbuf);
-			hwptr -= (unsigned) busaddr;
-			s->dma_dac.swptr = s->dma_dac.hwptr = hwptr;
-		}
-		swptr = s->dma_dac.swptr;
-		cnt = s->dma_dac.dmasize - swptr;
-		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-			cnt = s->dma_dac.dmasize - s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			start_dac(s);
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->dma_dac.wait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
-			continue;
-		}
-		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
-		swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_dac.swptr = swptr;
-		s->dma_dac.count += cnt;
-		s->dma_dac.endcleared = 0;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		start_dac(s);
-	}
-	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
-		  printk(KERN_INFO "cs4281: cs4281_write()- %Zd\n", ret));
-	return ret;
-}
-
-
-static unsigned int cs4281_poll(struct file *file,
-				struct poll_table_struct *wait)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
-		  printk(KERN_INFO "cs4281: cs4281_poll()+\n"));
-	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE) {
-		CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
-			  printk(KERN_INFO
-				 "cs4281: cs4281_poll() wait on FMODE_WRITE\n"));
-		if(!s->dma_dac.ready && prog_dmabuf_dac(s))
-			return 0;
-		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
-			  printk(KERN_INFO
-				 "cs4281: cs4281_poll() wait on FMODE_READ\n"));
-		if(!s->dma_dac.ready && prog_dmabuf_adc(s))
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	cs4281_update_ptr(s,CS_FALSE);
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >=
-			    (signed) s->dma_dac.fragsize) {
-				if (s->dma_dac.wakeup)
-					mask |= POLLOUT | POLLWRNORM;
-				else
-					mask = 0;
-				s->dma_dac.wakeup = 0;
-			}
-		} else {
-			if ((signed) (s->dma_dac.dmasize/2) >= s->dma_dac.count)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	} else if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= (signed) s->dma_adc.fragsize) 
-				mask |= POLLIN | POLLRDNORM;
-		} else {
-			if (s->dma_adc.count > 0)
-				mask |= POLLIN | POLLRDNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
-		  printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",
-			 mask));
-	return mask;
-}
-
-
-static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	struct dmabuf *db;
-	int ret;
-	unsigned long size;
-
-	CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
-		  printk(KERN_INFO "cs4281: cs4281_mmap()+\n"));
-
-	VALIDATE_STATE(s);
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf_dac(s)) != 0)
-			return ret;
-		db = &s->dma_dac;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf_adc(s)) != 0)
-			return ret;
-		db = &s->dma_adc;
-	} else
-		return -EINVAL;
-//
-// only support PLAYBACK for now
-//
-	db = &s->dma_dac;
-
-	if (cs4x_pgoff(vma) != 0)
-		return -EINVAL;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder))
-		return -EINVAL;
-	if (remap_pfn_range(vma, vma->vm_start,
-				virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
-				size, vma->vm_page_prot))
-		return -EAGAIN;
-	db->mapped = 1;
-
-	CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
-		  printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n",
-			 (unsigned) size));
-
-	return 0;
-}
-
-
-static int cs4281_ioctl(struct inode *inode, struct file *file,
-			unsigned int cmd, unsigned long arg)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	unsigned long flags;
-	audio_buf_info abinfo;
-	count_info cinfo;
-	int val, mapped, ret;
-	int __user *p = (int __user *)arg;
-
-	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
-		 "cs4281: cs4281_ioctl(): file=%p cmd=0x%.8x\n", file, cmd));
-#if CSDEBUG
-	cs_printioctl(cmd);
-#endif
-	VALIDATE_STATE(s);
-	mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-	    ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
-			"cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n",
-				 SOUND_VERSION));
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-		CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
-			 "cs4281: cs4281_ioctl(): DSP_SYNC\n"));
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s,
-					 0 /*file->f_flags & O_NONBLOCK */
-					 );
-		return 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
-				DSP_CAP_TRIGGER | DSP_CAP_MMAP,
-				p);
-
-	case SNDCTL_DSP_RESET:
-		CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
-			 "cs4281: cs4281_ioctl(): DSP_RESET\n"));
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq(s->irq);
-			s->dma_dac.swptr = s->dma_dac.hwptr =
-			    s->dma_dac.count = s->dma_dac.total_bytes =
-			    s->dma_dac.blocks = s->dma_dac.wakeup = 0;
-			prog_codec(s, CS_TYPE_DAC);
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq(s->irq);
-			s->dma_adc.swptr = s->dma_adc.hwptr =
-			    s->dma_adc.count = s->dma_adc.total_bytes =
-			    s->dma_adc.blocks = s->dma_dac.wakeup = 0;
-			prog_codec(s, CS_TYPE_ADC);
-		}
-		return 0;
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(val, p))
-			return -EFAULT;
-		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
-			 "cs4281: cs4281_ioctl(): DSP_SPEED val=%d\n", val));
-		//
-		// support independent capture and playback channels
-		// assume that the file mode bit determines the 
-		// direction of the data flow.
-		//
-		if (file->f_mode & FMODE_READ) {
-			if (val >= 0) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				// program sampling rates 
-				if (val > 48000)
-					val = 48000;
-				if (val < 6300)
-					val = 6300;
-				s->prop_adc.rate = val;
-				prog_codec(s, CS_TYPE_ADC);
-			}
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val >= 0) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				// program sampling rates 
-				if (val > 48000)
-					val = 48000;
-				if (val < 6300)
-					val = 6300;
-				s->prop_dac.rate = val;
-				prog_codec(s, CS_TYPE_DAC);
-			}
-		}
-
-		if (file->f_mode & FMODE_WRITE)
-			val = s->prop_dac.rate;
-		else if (file->f_mode & FMODE_READ)
-			val = s->prop_adc.rate;
-
-		return put_user(val, p);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(val, p))
-			return -EFAULT;
-		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
-			 "cs4281: cs4281_ioctl(): DSP_STEREO val=%d\n", val));
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ready = 0;
-			s->prop_adc.channels = val ? 2 : 1;
-			prog_codec(s, CS_TYPE_ADC);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ready = 0;
-			s->prop_dac.channels = val ? 2 : 1;
-			prog_codec(s, CS_TYPE_DAC);
-		}
-		return 0;
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, p))
-			return -EFAULT;
-		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
-			 "cs4281: cs4281_ioctl(): DSP_CHANNELS val=%d\n",
-				 val));
-		if (val != 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val >= 2)
-					s->prop_adc.channels = 2;
-				else
-					s->prop_adc.channels = 1;
-				prog_codec(s, CS_TYPE_ADC);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val >= 2)
-					s->prop_dac.channels = 2;
-				else
-					s->prop_dac.channels = 1;
-				prog_codec(s, CS_TYPE_DAC);
-			}
-		}
-
-		if (file->f_mode & FMODE_WRITE)
-			val = s->prop_dac.channels;
-		else if (file->f_mode & FMODE_READ)
-			val = s->prop_adc.channels;
-
-		return put_user(val, p);
-
-	case SNDCTL_DSP_GETFMTS:	// Returns a mask 
-		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
-			"cs4281: cs4281_ioctl(): DSP_GETFMT val=0x%.8x\n",
-				 AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
-				 AFMT_U8));
-		return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
-				AFMT_U8, p);
-
-	case SNDCTL_DSP_SETFMT:
-		if (get_user(val, p))
-			return -EFAULT;
-		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
-			 "cs4281: cs4281_ioctl(): DSP_SETFMT val=0x%.8x\n",
-				 val));
-		if (val != AFMT_QUERY) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val != AFMT_S16_LE
-				    && val != AFMT_U16_LE && val != AFMT_S8
-				    && val != AFMT_U8)
-					val = AFMT_U8;
-				s->prop_adc.fmt = val;
-				s->prop_adc.fmt_original = s->prop_adc.fmt;
-				prog_codec(s, CS_TYPE_ADC);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val != AFMT_S16_LE
-				    && val != AFMT_U16_LE && val != AFMT_S8
-				    && val != AFMT_U8)
-					val = AFMT_U8;
-				s->prop_dac.fmt = val;
-				s->prop_dac.fmt_original = s->prop_dac.fmt;
-				prog_codec(s, CS_TYPE_DAC);
-			}
-		} else {
-			if (file->f_mode & FMODE_WRITE)
-				val = s->prop_dac.fmt_original;
-			else if (file->f_mode & FMODE_READ)
-				val = s->prop_adc.fmt_original;
-		}
-		CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
-		  "cs4281: cs4281_ioctl(): DSP_SETFMT return val=0x%.8x\n", 
-			val));
-		return put_user(val, p);
-
-	case SNDCTL_DSP_POST:
-		CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
-			 "cs4281: cs4281_ioctl(): DSP_POST\n"));
-		return 0;
-
-	case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if (file->f_mode & s->ena & FMODE_READ)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & s->ena & FMODE_WRITE)
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, p);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready
-				    && (ret = prog_dmabuf_adc(s)))
-					return ret;
-				start_adc(s);
-			} else
-				stop_adc(s);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac.ready
-				    && (ret = prog_dmabuf_dac(s)))
-					return ret;
-				start_dac(s);
-			} else
-				stop_dac(s);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)))
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		cs4281_update_ptr(s,CS_FALSE);
-		abinfo.fragsize = s->dma_dac.fragsize;
-		if (s->dma_dac.mapped)
-			abinfo.bytes = s->dma_dac.dmasize;
-		else
-			abinfo.bytes =
-			    s->dma_dac.dmasize - s->dma_dac.count;
-		abinfo.fragstotal = s->dma_dac.numfrag;
-		abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
-		CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO
-			"cs4281: cs4281_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n",
-				abinfo.fragsize,abinfo.bytes,abinfo.fragstotal,
-				abinfo.fragments));
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(p, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)))
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		cs4281_update_ptr(s,CS_FALSE);
-		if (s->conversion) {
-			abinfo.fragsize = s->dma_adc.fragsize / 2;
-			abinfo.bytes = s->dma_adc.count / 2;
-			abinfo.fragstotal = s->dma_adc.numfrag;
-			abinfo.fragments =
-			    abinfo.bytes >> (s->dma_adc.fragshift - 1);
-		} else {
-			abinfo.fragsize = s->dma_adc.fragsize;
-			abinfo.bytes = s->dma_adc.count;
-			abinfo.fragstotal = s->dma_adc.numfrag;
-			abinfo.fragments =
-			    abinfo.bytes >> s->dma_adc.fragshift;
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(p, &abinfo,
-				    sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_NONBLOCK:
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if(!s->dma_dac.ready && prog_dmabuf_dac(s))
-			return 0;
-		spin_lock_irqsave(&s->lock, flags);
-		cs4281_update_ptr(s,CS_FALSE);
-		val = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, p);
-
-	case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if(!s->dma_adc.ready && prog_dmabuf_adc(s))
-			return 0;
-		spin_lock_irqsave(&s->lock, flags);
-		cs4281_update_ptr(s,CS_FALSE);
-		cinfo.bytes = s->dma_adc.total_bytes;
-		if (s->dma_adc.mapped) {
-			cinfo.blocks =
-			    (cinfo.bytes >> s->dma_adc.fragshift) -
-			    s->dma_adc.blocks;
-			s->dma_adc.blocks =
-			    cinfo.bytes >> s->dma_adc.fragshift;
-		} else {
-			if (s->conversion) {
-				cinfo.blocks =
-				    s->dma_adc.count /
-				    2 >> (s->dma_adc.fragshift - 1);
-			} else
-				cinfo.blocks =
-				    s->dma_adc.count >> s->dma_adc.
-				    fragshift;
-		}
-		if (s->conversion)
-			cinfo.ptr = s->dma_adc.hwptr / 2;
-		else
-			cinfo.ptr = s->dma_adc.hwptr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= s->dma_adc.fragsize - 1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(p, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-	case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if(!s->dma_dac.ready && prog_dmabuf_dac(s))
-			return 0;
-		spin_lock_irqsave(&s->lock, flags);
-		cs4281_update_ptr(s,CS_FALSE);
-		cinfo.bytes = s->dma_dac.total_bytes;
-		if (s->dma_dac.mapped) {
-			cinfo.blocks =
-			    (cinfo.bytes >> s->dma_dac.fragshift) -
-			    s->dma_dac.blocks;
-			s->dma_dac.blocks =
-			    cinfo.bytes >> s->dma_dac.fragshift;
-		} else {
-			cinfo.blocks =
-			    s->dma_dac.count >> s->dma_dac.fragshift;
-		}
-		cinfo.ptr = s->dma_dac.hwptr;
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= s->dma_dac.fragsize - 1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(p, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf_dac(s)))
-				return val;
-			return put_user(s->dma_dac.fragsize, p);
-		}
-		if ((val = prog_dmabuf_adc(s)))
-			return val;
-		if (s->conversion)
-			return put_user(s->dma_adc.fragsize / 2, p);
-		else
-			return put_user(s->dma_adc.fragsize, p);
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, p))
-			return -EFAULT;
-		return 0;	// Say OK, but do nothing.
-
-	case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision)
-		    || (file->f_mode & FMODE_WRITE
-			&& s->dma_dac.subdivision)) return -EINVAL;
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
-		else if (file->f_mode & FMODE_WRITE)
-			s->dma_dac.subdivision = val;
-		return 0;
-
-	case SOUND_PCM_READ_RATE:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->prop_adc.rate, p);
-		else if (file->f_mode & FMODE_WRITE)
-			return put_user(s->prop_dac.rate, p);
-
-	case SOUND_PCM_READ_CHANNELS:
-		if (file->f_mode & FMODE_READ)
-			return put_user(s->prop_adc.channels, p);
-		else if (file->f_mode & FMODE_WRITE)
-			return put_user(s->prop_dac.channels, p);
-
-	case SOUND_PCM_READ_BITS:
-		if (file->f_mode & FMODE_READ)
-			return
-			    put_user(
-				     (s->prop_adc.
-				      fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
-				     p);
-		else if (file->f_mode & FMODE_WRITE)
-			return
-			    put_user(
-				     (s->prop_dac.
-				      fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
-				     p);
-
-	case SOUND_PCM_WRITE_FILTER:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_READ_FILTER:
-		return -EINVAL;
-	}
-	return mixer_ioctl(s, cmd, arg);
-}
-
-
-static int cs4281_release(struct inode *inode, struct file *file)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-
-	CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO
-		 "cs4281: cs4281_release(): inode=%p file=%p f_mode=%d\n",
-			 inode, file, file->f_mode));
-
-	VALIDATE_STATE(s);
-
-	if (file->f_mode & FMODE_WRITE) {
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-		mutex_lock(&s->open_sem_dac);
-		stop_dac(s);
-		dealloc_dmabuf(s, &s->dma_dac);
-		s->open_mode &= ~FMODE_WRITE;
-		mutex_unlock(&s->open_sem_dac);
-		wake_up(&s->open_wait_dac);
-	}
-	if (file->f_mode & FMODE_READ) {
-		drain_adc(s, file->f_flags & O_NONBLOCK);
-		mutex_lock(&s->open_sem_adc);
-		stop_adc(s);
-		dealloc_dmabuf(s, &s->dma_adc);
-		s->open_mode &= ~FMODE_READ;
-		mutex_unlock(&s->open_sem_adc);
-		wake_up(&s->open_wait_adc);
-	}
-	return 0;
-}
-
-static int cs4281_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct cs4281_state *s=NULL;
-	struct list_head *entry;
-
-	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
-		"cs4281: cs4281_open(): inode=%p file=%p f_mode=0x%x\n",
-			inode, file, file->f_mode));
-
-	list_for_each(entry, &cs4281_devs)
-	{
-		s = list_entry(entry, struct cs4281_state, list);
-
-		if (!((s->dev_audio ^ minor) & ~0xf))
-			break;
-	}
-	if (entry == &cs4281_devs)
-		return -ENODEV;
-	if (!s) {
-		CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
-			"cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
-		return -ENODEV;
-	}
-	VALIDATE_STATE(s);
-	file->private_data = s;
-
-	// wait for device to become free 
-	if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
-		CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO
-			 "cs4281: cs4281_open(): Error - must open READ and/or WRITE\n"));
-		return -ENODEV;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		mutex_lock(&s->open_sem_dac);
-		while (s->open_mode & FMODE_WRITE) {
-			if (file->f_flags & O_NONBLOCK) {
-				mutex_unlock(&s->open_sem_dac);
-				return -EBUSY;
-			}
-			mutex_unlock(&s->open_sem_dac);
-			interruptible_sleep_on(&s->open_wait_dac);
-
-			if (signal_pending(current))
-				return -ERESTARTSYS;
-			mutex_lock(&s->open_sem_dac);
-		}
-	}
-	if (file->f_mode & FMODE_READ) {
-		mutex_lock(&s->open_sem_adc);
-		while (s->open_mode & FMODE_READ) {
-			if (file->f_flags & O_NONBLOCK) {
-				mutex_unlock(&s->open_sem_adc);
-				return -EBUSY;
-			}
-			mutex_unlock(&s->open_sem_adc);
-			interruptible_sleep_on(&s->open_wait_adc);
-
-			if (signal_pending(current))
-				return -ERESTARTSYS;
-			mutex_lock(&s->open_sem_adc);
-		}
-	}
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	if (file->f_mode & FMODE_READ) {
-		s->prop_adc.fmt = AFMT_U8;
-		s->prop_adc.fmt_original = s->prop_adc.fmt;
-		s->prop_adc.channels = 1;
-		s->prop_adc.rate = 8000;
-		s->prop_adc.clkdiv = 96 | 0x80;
-		s->conversion = 0;
-		s->ena &= ~FMODE_READ;
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
-		    s->dma_adc.subdivision = 0;
-		mutex_unlock(&s->open_sem_adc);
-
-		if (prog_dmabuf_adc(s)) {
-			CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
-				"cs4281: adc Program dmabufs failed.\n"));
-			cs4281_release(inode, file);
-			return -ENOMEM;
-		}
-		prog_codec(s, CS_TYPE_ADC);
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		s->prop_dac.fmt = AFMT_U8;
-		s->prop_dac.fmt_original = s->prop_dac.fmt;
-		s->prop_dac.channels = 1;
-		s->prop_dac.rate = 8000;
-		s->prop_dac.clkdiv = 96 | 0x80;
-		s->conversion = 0;
-		s->ena &= ~FMODE_WRITE;
-		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
-		    s->dma_dac.subdivision = 0;
-		mutex_unlock(&s->open_sem_dac);
-
-		if (prog_dmabuf_dac(s)) {
-			CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
-				"cs4281: dac Program dmabufs failed.\n"));
-			cs4281_release(inode, file);
-			return -ENOMEM;
-		}
-		prog_codec(s, CS_TYPE_DAC);
-	}
-	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
-		  printk(KERN_INFO "cs4281: cs4281_open()- 0\n"));
-	return nonseekable_open(inode, file);
-}
-
-
-// ******************************************************************************************
-//   Wave (audio) file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_audio_fops = {
-	.owner	 = THIS_MODULE,
-	.llseek	 = no_llseek,
-	.read	 = cs4281_read,
-	.write	 = cs4281_write,
-	.poll	 = cs4281_poll,
-	.ioctl	 = cs4281_ioctl,
-	.mmap	 = cs4281_mmap,
-	.open	 = cs4281_open,
-	.release = cs4281_release,
-};
-
-// --------------------------------------------------------------------- 
-
-// hold spinlock for the following! 
-static void cs4281_handle_midi(struct cs4281_state *s)
-{
-	unsigned char ch;
-	int wake;
-	unsigned temp1;
-
-	wake = 0;
-	while (!(readl(s->pBA0 + BA0_MIDSR) & 0x80)) {
-		ch = readl(s->pBA0 + BA0_MIDRP);
-		if (s->midi.icnt < MIDIINBUF) {
-			s->midi.ibuf[s->midi.iwr] = ch;
-			s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
-			s->midi.icnt++;
-		}
-		wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.iwait);
-	wake = 0;
-	while (!(readl(s->pBA0 + BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) {
-		temp1 = (s->midi.obuf[s->midi.ord]) & 0x000000ff;
-		writel(temp1, s->pBA0 + BA0_MIDWP);
-		s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
-		s->midi.ocnt--;
-		if (s->midi.ocnt < MIDIOUTBUF - 16)
-			wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.owait);
-}
-
-
-
-static irqreturn_t cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct cs4281_state *s = (struct cs4281_state *) dev_id;
-	unsigned int temp1;
-
-	// fastpath out, to ease interrupt sharing 
-	temp1 = readl(s->pBA0 + BA0_HISR);	// Get Int Status reg.
-
-	CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO
-		  "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n", temp1));
-/*
-* If not DMA or MIDI interrupt, then just return.
-*/
-	if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) {
-		writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
-		CS_DBGOUT(CS_INTERRUPT, 9, printk(KERN_INFO
-			"cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n"));
-		return IRQ_NONE;
-	}
-
-	if (temp1 & HISR_DMA0)	// If play interrupt,
-		readl(s->pBA0 + BA0_HDSR0);	//   clear the source.
-
-	if (temp1 & HISR_DMA1)	// Same for play.
-		readl(s->pBA0 + BA0_HDSR1);
-	writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);	// Local EOI
-
-	spin_lock(&s->lock);
-	cs4281_update_ptr(s,CS_TRUE);
-	cs4281_handle_midi(s);
-	spin_unlock(&s->lock);
-	return IRQ_HANDLED;
-}
-
-// **************************************************************************
-
-static void cs4281_midi_timer(unsigned long data)
-{
-	struct cs4281_state *s = (struct cs4281_state *) data;
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	cs4281_handle_midi(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->midi.timer.expires = jiffies + 1;
-	add_timer(&s->midi.timer);
-}
-
-
-// --------------------------------------------------------------------- 
-
-static ssize_t cs4281_midi_read(struct file *file, char __user *buffer,
-				size_t count, loff_t * ppos)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.ird;
-		cnt = MIDIINBUF - ptr;
-		if (s->midi.icnt < cnt)
-			cnt = s->midi.icnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.iwait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
-			continue;
-		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
-			return ret ? ret : -EFAULT;
-		ptr = (ptr + cnt) % MIDIINBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.ird = ptr;
-		s->midi.icnt -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-	}
-	return ret;
-}
-
-
-static ssize_t cs4281_midi_write(struct file *file, const char __user *buffer,
-				 size_t count, loff_t * ppos)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	ret = 0;
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.owr;
-		cnt = MIDIOUTBUF - ptr;
-		if (s->midi.ocnt + cnt > MIDIOUTBUF)
-			cnt = MIDIOUTBUF - s->midi.ocnt;
-		if (cnt <= 0)
-			cs4281_handle_midi(s);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK)
-				return ret ? ret : -EAGAIN;
-			interruptible_sleep_on(&s->midi.owait);
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
-			continue;
-		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
-			return ret ? ret : -EFAULT;
-		ptr = (ptr + cnt) % MIDIOUTBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.owr = ptr;
-		s->midi.ocnt += cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		spin_lock_irqsave(&s->lock, flags);
-		cs4281_handle_midi(s);
-		spin_unlock_irqrestore(&s->lock, flags);
-	}
-	return ret;
-}
-
-
-static unsigned int cs4281_midi_poll(struct file *file,
-				     struct poll_table_struct *wait)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_flags & FMODE_WRITE)
-		poll_wait(file, &s->midi.owait, wait);
-	if (file->f_flags & FMODE_READ)
-		poll_wait(file, &s->midi.iwait, wait);
-	spin_lock_irqsave(&s->lock, flags);
-	if (file->f_flags & FMODE_READ) {
-		if (s->midi.icnt > 0)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_flags & FMODE_WRITE) {
-		if (s->midi.ocnt < MIDIOUTBUF)
-			mask |= POLLOUT | POLLWRNORM;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-
-static int cs4281_midi_open(struct inode *inode, struct file *file)
-{
-	unsigned long flags, temp1;
-	unsigned int minor = iminor(inode);
-	struct cs4281_state *s=NULL;
-	struct list_head *entry;
-	list_for_each(entry, &cs4281_devs)
-	{
-		s = list_entry(entry, struct cs4281_state, list);
-
-		if (s->dev_midi == minor)
-			break;
-	}
-
-	if (entry == &cs4281_devs)
-		return -ENODEV;
-	if (!s)
-	{
-		CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
-			"cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
-		return -ENODEV;
-	}
-	VALIDATE_STATE(s);
-	file->private_data = s;
-	// wait for device to become free 
-	mutex_lock(&s->open_sem);
-	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_sem);
-			return -EBUSY;
-		}
-		mutex_unlock(&s->open_sem);
-		interruptible_sleep_on(&s->open_wait);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_sem);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-		writel(1, s->pBA0 + BA0_MIDCR);	// Reset the interface.
-		writel(0, s->pBA0 + BA0_MIDCR);	// Return to normal mode.
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-		writel(0x0000000f, s->pBA0 + BA0_MIDCR);	// Enable transmit, record, ints.
-		temp1 = readl(s->pBA0 + BA0_HIMR);
-		writel(temp1 & 0xffbfffff, s->pBA0 + BA0_HIMR);	// Enable midi int. recognition.
-		writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);	// Enable interrupts
-		init_timer(&s->midi.timer);
-		s->midi.timer.expires = jiffies + 1;
-		s->midi.timer.data = (unsigned long) s;
-		s->midi.timer.function = cs4281_midi_timer;
-		add_timer(&s->midi.timer);
-	}
-	if (file->f_mode & FMODE_READ) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->open_mode |=
-	    (file->
-	     f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ |
-					    FMODE_MIDI_WRITE);
-	mutex_unlock(&s->open_sem);
-	return nonseekable_open(inode, file);
-}
-
-
-static int cs4281_midi_release(struct inode *inode, struct file *file)
-{
-	struct cs4281_state *s =
-	    (struct cs4281_state *) file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	unsigned count, tmo;
-
-	VALIDATE_STATE(s);
-
-	if (file->f_mode & FMODE_WRITE) {
-		add_wait_queue(&s->midi.owait, &wait);
-		for (;;) {
-			set_current_state(TASK_INTERRUPTIBLE);
-			spin_lock_irqsave(&s->lock, flags);
-			count = s->midi.ocnt;
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (count <= 0)
-				break;
-			if (signal_pending(current))
-				break;
-			if (file->f_flags & O_NONBLOCK) {
-				remove_wait_queue(&s->midi.owait, &wait);
-				current->state = TASK_RUNNING;
-				return -EBUSY;
-			}
-			tmo = (count * HZ) / 3100;
-			if (!schedule_timeout(tmo ? : 1) && tmo)
-				printk(KERN_DEBUG
-				       "cs4281: midi timed out??\n");
-		}
-		remove_wait_queue(&s->midi.owait, &wait);
-		current->state = TASK_RUNNING;
-	}
-	mutex_lock(&s->open_sem);
-	s->open_mode &=
-	    (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ |
-						     FMODE_MIDI_WRITE);
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		writel(0, s->pBA0 + BA0_MIDCR);	// Disable Midi interrupts.  
-		del_timer(&s->midi.timer);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	mutex_unlock(&s->open_sem);
-	wake_up(&s->open_wait);
-	return 0;
-}
-
-// ******************************************************************************************
-//   Midi file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_midi_fops = {
-	.owner	 = THIS_MODULE,
-	.llseek	 = no_llseek,
-	.read	 = cs4281_midi_read,
-	.write	 = cs4281_midi_write,
-	.poll	 = cs4281_midi_poll,
-	.open	 = cs4281_midi_open,
-	.release = cs4281_midi_release,
-};
-
-
-// --------------------------------------------------------------------- 
-
-// maximum number of devices 
-#define NR_DEVICE 8		// Only eight devices supported currently.
-
-// --------------------------------------------------------------------- 
-
-static struct initvol {
-	int mixch;
-	int vol;
-} initvol[] __devinitdata = {
-
-	{
-	SOUND_MIXER_WRITE_VOLUME, 0x4040}, {
-	SOUND_MIXER_WRITE_PCM, 0x4040}, {
-	SOUND_MIXER_WRITE_SYNTH, 0x4040}, {
-	SOUND_MIXER_WRITE_CD, 0x4040}, {
-	SOUND_MIXER_WRITE_LINE, 0x4040}, {
-	SOUND_MIXER_WRITE_LINE1, 0x4040}, {
-	SOUND_MIXER_WRITE_RECLEV, 0x0000}, {
-	SOUND_MIXER_WRITE_SPEAKER, 0x4040}, {
-	SOUND_MIXER_WRITE_MIC, 0x0000}
-};
-
-
-#ifndef NOT_CS4281_PM
-static void __devinit cs4281_BuildFIFO(
-	struct cs4281_pipeline *p, 
-	struct cs4281_state *s)
-{
-	switch(p->number)
-	{
-		case 0:  /* playback */
-		{
-			p->u32FCRnAddress  =  BA0_FCR0;
-			p->u32FSICnAddress = BA0_FSIC0;
-			p->u32FPDRnAddress = BA0_FPDR0;
-			break;
-		}
-		case 1:  /* capture */
-		{
-			p->u32FCRnAddress  =  BA0_FCR1;
-			p->u32FSICnAddress = BA0_FSIC1;
-			p->u32FPDRnAddress = BA0_FPDR1;
-			break;
-		}
-
-		case 2: 
-		{
-			p->u32FCRnAddress  =  BA0_FCR2;
-			p->u32FSICnAddress = BA0_FSIC2;
-			p->u32FPDRnAddress = BA0_FPDR2;
-			break;
-		}
-		case 3: 
-		{
-			p->u32FCRnAddress  =  BA0_FCR3;
-			p->u32FSICnAddress = BA0_FSIC3;
-			p->u32FPDRnAddress = BA0_FPDR3;
-			break;
-		}
-		default:
-			break;
-	}
-	//
-	// first read the hardware to initialize the member variables
-	//
-	p->u32FCRnValue = readl(s->pBA0 + p->u32FCRnAddress);
-	p->u32FSICnValue = readl(s->pBA0 + p->u32FSICnAddress);
-	p->u32FPDRnValue = readl(s->pBA0 + p->u32FPDRnAddress);
-
-}
-
-static void __devinit cs4281_BuildDMAengine(
-	struct cs4281_pipeline *p, 
-	struct cs4281_state *s)
-{
-/*
-* initialize all the addresses of this pipeline dma info.
-*/
-	switch(p->number)
-	{
-		case 0:  /* playback */
-		{
-			p->u32DBAnAddress = BA0_DBA0;
-			p->u32DCAnAddress = BA0_DCA0;
-			p->u32DBCnAddress = BA0_DBC0;
-			p->u32DCCnAddress = BA0_DCC0;
-			p->u32DMRnAddress = BA0_DMR0;
-			p->u32DCRnAddress = BA0_DCR0;
-			p->u32HDSRnAddress = BA0_HDSR0;
-			break;
-		}
-
-		case 1: /* capture */
-		{
-			p->u32DBAnAddress = BA0_DBA1;
-			p->u32DCAnAddress = BA0_DCA1;
-			p->u32DBCnAddress = BA0_DBC1;
-			p->u32DCCnAddress = BA0_DCC1;
-			p->u32DMRnAddress = BA0_DMR1;
-			p->u32DCRnAddress = BA0_DCR1;
-			p->u32HDSRnAddress = BA0_HDSR1;
-			break;
-		}
-
-		case 2:
-		{
-			p->u32DBAnAddress = BA0_DBA2;
-			p->u32DCAnAddress = BA0_DCA2;
-			p->u32DBCnAddress = BA0_DBC2;
-			p->u32DCCnAddress = BA0_DCC2;
-			p->u32DMRnAddress = BA0_DMR2;
-			p->u32DCRnAddress = BA0_DCR2;
-			p->u32HDSRnAddress = BA0_HDSR2;
-			break;
-		}
-
-		case 3:
-		{
-			p->u32DBAnAddress = BA0_DBA3;
-			p->u32DCAnAddress = BA0_DCA3;
-			p->u32DBCnAddress = BA0_DBC3;
-			p->u32DCCnAddress = BA0_DCC3;
-			p->u32DMRnAddress = BA0_DMR3;
-			p->u32DCRnAddress = BA0_DCR3;
-			p->u32HDSRnAddress = BA0_HDSR3;
-			break;
-		}
-		default:
-			break;
-	}
-
-//
-// Initialize the dma values for this pipeline
-//
-	p->u32DBAnValue = readl(s->pBA0 + p->u32DBAnAddress);
-	p->u32DBCnValue = readl(s->pBA0 + p->u32DBCnAddress);
-	p->u32DMRnValue = readl(s->pBA0 + p->u32DMRnAddress);
-	p->u32DCRnValue = readl(s->pBA0 + p->u32DCRnAddress);
-
-}
-
-static void __devinit cs4281_InitPM(struct cs4281_state *s)
-{
-	int i;
-	struct cs4281_pipeline *p;
-
-	for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
-	{
-		p = &s->pl[i];
-		p->number = i;
-		cs4281_BuildDMAengine(p,s);
-		cs4281_BuildFIFO(p,s);
-	/*
-	* currently only  2 pipelines are used
-	* so, only set the valid bit on the playback and capture.
-	*/
-		if( (i == CS4281_PLAYBACK_PIPELINE_NUMBER) || 
-			(i == CS4281_CAPTURE_PIPELINE_NUMBER))
-			p->flags |= CS4281_PIPELINE_VALID;
-	}
-	s->pm.u32SSPM_BITS = 0x7e;  /* rev c, use 0x7c for rev a or b */
-}
-#endif
-
-static int __devinit cs4281_probe(struct pci_dev *pcidev,
-				  const struct pci_device_id *pciid)
-{
-	struct cs4281_state *s;
-	dma_addr_t dma_mask;
-	mm_segment_t fs;
-	int i, val;
-	unsigned int temp1, temp2;
-
-	CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
-		  printk(KERN_INFO "cs4281: probe()+\n"));
-
-	if (pci_enable_device(pcidev)) {
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
-			 "cs4281: pci_enable_device() failed\n"));
-		return -1;
-	}
-	if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM) ||
-	    !(pci_resource_flags(pcidev, 1) & IORESOURCE_MEM)) {
-		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
-			 "cs4281: probe()- Memory region not assigned\n"));
-		return -ENODEV;
-	}
-	if (pcidev->irq == 0) {
-		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
-			 "cs4281: probe() IRQ not assigned\n"));
-		return -ENODEV;
-	}
-	dma_mask = 0xffffffff;	/* this enables playback and recording */
-	i = pci_set_dma_mask(pcidev, dma_mask);
-	if (i) {
-		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
-		      "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n"));
-		return i;
-	}
-	if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) {
-		CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
-		      "cs4281: probe() no memory for state struct.\n"));
-		return -1;
-	}
-	memset(s, 0, sizeof(struct cs4281_state));
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac.wait);
-	init_waitqueue_head(&s->open_wait);
-	init_waitqueue_head(&s->open_wait_adc);
-	init_waitqueue_head(&s->open_wait_dac);
-	init_waitqueue_head(&s->midi.iwait);
-	init_waitqueue_head(&s->midi.owait);
-	mutex_init(&s->open_sem);
-	mutex_init(&s->open_sem_adc);
-	mutex_init(&s->open_sem_dac);
-	spin_lock_init(&s->lock);
-	s->pBA0phys = pci_resource_start(pcidev, 0);
-	s->pBA1phys = pci_resource_start(pcidev, 1);
-
-	/* Convert phys to linear. */
-	s->pBA0 = ioremap_nocache(s->pBA0phys, 4096);
-	if (!s->pBA0) {
-		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
-			 "cs4281: BA0 I/O mapping failed. Skipping part.\n"));
-		goto err_free;
-	}
-	s->pBA1 = ioremap_nocache(s->pBA1phys, 65536);
-	if (!s->pBA1) {
-		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
-			 "cs4281: BA1 I/O mapping failed. Skipping part.\n"));
-		goto err_unmap;
-	}
-
-	temp1 = readl(s->pBA0 + BA0_PCICFG00);
-	temp2 = readl(s->pBA0 + BA0_PCICFG04);
-
-	CS_DBGOUT(CS_INIT, 2,
-		  printk(KERN_INFO
-			 "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=%p pBA1=%p \n",
-			 (unsigned) temp1, (unsigned) temp2, s->pBA0, s->pBA1));
-	CS_DBGOUT(CS_INIT, 2,
-		  printk(KERN_INFO
-			 "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
-			 (unsigned) s->pBA0phys, (unsigned) s->pBA1phys));
-
-#ifndef NOT_CS4281_PM
-	s->pm.flags = CS4281_PM_IDLE;
-#endif
-	temp1 = cs4281_hw_init(s);
-	if (temp1) {
-		CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
-			 "cs4281: cs4281_hw_init() failed. Skipping part.\n"));
-		goto err_irq;
-	}
-	s->magic = CS4281_MAGIC;
-	s->pcidev = pcidev;
-	s->irq = pcidev->irq;
-	if (request_irq
-	    (s->irq, cs4281_interrupt, IRQF_SHARED, "Crystal CS4281", s)) {
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1,
-			  printk(KERN_ERR "cs4281: irq %u in use\n", s->irq));
-		goto err_irq;
-	}
-	if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) <
-	    0) {
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
-			 "cs4281: probe() register_sound_dsp() failed.\n"));
-		goto err_dev1;
-	}
-	if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) <
-	    0) {
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
-			 "cs4281: probe() register_sound_mixer() failed.\n"));
-		goto err_dev2;
-	}
-	if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0) {
-		CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
-			 "cs4281: probe() register_sound_midi() failed.\n"));
-		goto err_dev3;
-	}
-#ifndef NOT_CS4281_PM
-	cs4281_InitPM(s);
-	s->pm.flags |= CS4281_PM_NOT_REGISTERED;
-#endif
-
-	pci_set_master(pcidev);	// enable bus mastering 
-
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	val = SOUND_MASK_LINE;
-	mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val);
-	for (i = 0; i < sizeof(initvol) / sizeof(initvol[0]); i++) {
-		val = initvol[i].vol;
-		mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val);
-	}
-	val = 1;		// enable mic preamp 
-	mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val);
-	set_fs(fs);
-
-	pci_set_drvdata(pcidev, s);
-	list_add(&s->list, &cs4281_devs);
-	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
-		"cs4281: probe()- device allocated successfully\n"));
-	return 0;
-
-      err_dev3:
-	unregister_sound_mixer(s->dev_mixer);
-      err_dev2:
-	unregister_sound_dsp(s->dev_audio);
-      err_dev1:
-	free_irq(s->irq, s);
-      err_irq:
-	iounmap(s->pBA1);
-      err_unmap:
-	iounmap(s->pBA0);
-      err_free:
-	kfree(s);
-
-	CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
-		"cs4281: probe()- no device allocated\n"));
-	return -ENODEV;
-} // probe_cs4281
-
-
-// --------------------------------------------------------------------- 
-
-static void __devexit cs4281_remove(struct pci_dev *pci_dev)
-{
-	struct cs4281_state *s = pci_get_drvdata(pci_dev);
-	// stop DMA controller 
-	synchronize_irq(s->irq);
-	free_irq(s->irq, s);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->dev_mixer);
-	unregister_sound_midi(s->dev_midi);
-	iounmap(s->pBA1);
-	iounmap(s->pBA0);
-	pci_set_drvdata(pci_dev,NULL);
-	list_del(&s->list);
-	kfree(s);
-	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
-		 "cs4281: cs4281_remove()-: remove successful\n"));
-}
-
-static struct pci_device_id cs4281_pci_tbl[] = {
-	{
-		.vendor    = PCI_VENDOR_ID_CIRRUS,
-		.device    = PCI_DEVICE_ID_CRYSTAL_CS4281,
-		.subvendor = PCI_ANY_ID,
-		.subdevice = PCI_ANY_ID,
-	},
-	{ 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, cs4281_pci_tbl);
-
-static struct pci_driver cs4281_pci_driver = {
-	.name	  = "cs4281",
-	.id_table = cs4281_pci_tbl,
-	.probe	  = cs4281_probe,
-	.remove	  = __devexit_p(cs4281_remove),
-	.suspend  = CS4281_SUSPEND_TBL,
-	.resume	  = CS4281_RESUME_TBL,
-};
-
-static int __init cs4281_init_module(void)
-{
-	int rtn = 0;
-	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO 
-		"cs4281: cs4281_init_module()+ \n"));
-	printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " "
-	       __DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION,
-	       CS4281_ARCH);
-	rtn = pci_register_driver(&cs4281_pci_driver);
-
-	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn));
-	return rtn;
-}
-
-static void __exit cs4281_cleanup_module(void)
-{
-	pci_unregister_driver(&cs4281_pci_driver);
-	CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
-		  printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n"));
-}
-// --------------------------------------------------------------------- 
-
-MODULE_AUTHOR("gw boynton, audio@crystal.cirrus.com");
-MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver");
-MODULE_LICENSE("GPL");
-
-// --------------------------------------------------------------------- 
-
-module_init(cs4281_init_module);
-module_exit(cs4281_cleanup_module);
-
diff --git a/sound/oss/cs4281/cs4281pm-24.c b/sound/oss/cs4281/cs4281pm-24.c
deleted file mode 100644
index 90cbd76..0000000
--- a/sound/oss/cs4281/cs4281pm-24.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
-*
-*      "cs4281pm.c" --  Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-*      Copyright (C) 2000,2001  Cirrus Logic Corp.  
-*            -- tom woller (twoller@crystal.cirrus.com) or
-*               (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* 12/22/00 trw - new file. 
-*
-*******************************************************************************/
-
-#ifndef NOT_CS4281_PM
-#include <linux/pm.h>
-
-static int cs4281_suspend(struct cs4281_state *s);
-static int cs4281_resume(struct cs4281_state *s);
-/* 
-* for now (12/22/00) only enable the pm_register PM support.
-* allow these table entries to be null.
-#define CS4281_SUSPEND_TBL cs4281_suspend_tbl
-#define CS4281_RESUME_TBL cs4281_resume_tbl
-*/
-#define CS4281_SUSPEND_TBL cs4281_suspend_null
-#define CS4281_RESUME_TBL cs4281_resume_null
-
-#else /* CS4281_PM */
-#define CS4281_SUSPEND_TBL cs4281_suspend_null
-#define CS4281_RESUME_TBL cs4281_resume_null
-#endif /* CS4281_PM */
-
diff --git a/sound/oss/cs4281/cs4281pm.h b/sound/oss/cs4281/cs4281pm.h
deleted file mode 100644
index b44fdc9..0000000
--- a/sound/oss/cs4281/cs4281pm.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef NOT_CS4281_PM
-/*******************************************************************************
-*
-*      "cs4281pm.h" --  Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-*      Copyright (C) 2000,2001  Cirrus Logic Corp.  
-*            -- tom woller (twoller@crystal.cirrus.com) or
-*               (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* 12/22/00 trw - new file. 
-*
-*******************************************************************************/
-/* general pm definitions */
-#define CS4281_AC97_HIGHESTREGTORESTORE 0x26
-#define CS4281_AC97_NUMBER_RESTORE_REGS (CS4281_AC97_HIGHESTREGTORESTORE/2-1)
-
-/* pipeline definitions */
-#define CS4281_NUMBER_OF_PIPELINES 	4
-#define CS4281_PIPELINE_VALID 		0x0001
-#define CS4281_PLAYBACK_PIPELINE_NUMBER	0x0000
-#define CS4281_CAPTURE_PIPELINE_NUMBER 	0x0001
-
-/* PM state defintions */
-#define CS4281_PM_NOT_REGISTERED	0x1000
-#define CS4281_PM_IDLE			0x0001
-#define CS4281_PM_SUSPENDING		0x0002
-#define CS4281_PM_SUSPENDED		0x0004
-#define CS4281_PM_RESUMING		0x0008
-#define CS4281_PM_RESUMED		0x0010
-
-struct cs4281_pm {
-	unsigned long flags;
-	u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue;
-	u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR;
-	u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save;
-	u32 u32SSPM_BITS;
-	u32 ac97[CS4281_AC97_NUMBER_RESTORE_REGS];
-	u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono;
-	u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose;
-	u32 u32hwptr_playback,u32hwptr_capture;
-};
-
-struct cs4281_pipeline {
-	unsigned flags;
-	unsigned number;
-	u32 u32DBAnValue,u32DBCnValue,u32DMRnValue,u32DCRnValue;
-	u32 u32DBAnAddress,u32DCAnAddress,u32DBCnAddress,u32DCCnAddress;
-	u32 u32DMRnAddress,u32DCRnAddress,u32HDSRnAddress;
-	u32 u32DBAn_Save,u32DBCn_Save,u32DMRn_Save,u32DCRn_Save;
-	u32 u32DCCn_Save,u32DCAn_Save;
-/* 
-* technically, these are fifo variables, but just map the 
-* first fifo with the first pipeline and then use the fifo
-* variables inside of the pipeline struct.
-*/
-	u32 u32FCRn_Save,u32FSICn_Save;
-	u32 u32FCRnValue,u32FCRnAddress,u32FSICnValue,u32FSICnAddress;
-	u32 u32FPDRnValue,u32FPDRnAddress;
-};
-#endif
diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c
index fb64279..08274c9 100644
--- a/sound/oss/dev_table.c
+++ b/sound/oss/dev_table.c
@@ -13,9 +13,39 @@
 
 #include <linux/init.h>
 
-#define _DEV_TABLE_C_
 #include "sound_config.h"
 
+struct audio_operations *audio_devs[MAX_AUDIO_DEV];
+EXPORT_SYMBOL(audio_devs);
+
+int num_audiodevs;
+EXPORT_SYMBOL(num_audiodevs);
+
+struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
+EXPORT_SYMBOL(mixer_devs);
+
+int num_mixers;
+EXPORT_SYMBOL(num_mixers);
+
+struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
+EXPORT_SYMBOL(synth_devs);
+
+int num_synths;
+
+struct midi_operations *midi_devs[MAX_MIDI_DEV];
+EXPORT_SYMBOL(midi_devs);
+
+int num_midis;
+EXPORT_SYMBOL(num_midis);
+
+struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
+	&default_sound_timer, NULL
+};
+EXPORT_SYMBOL(sound_timer_devs);
+
+int num_sound_timers = 1;
+
+
 static int sound_alloc_audiodev(void);
 
 int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
@@ -75,6 +105,7 @@
 	audio_init_devices();
 	return num;
 }
+EXPORT_SYMBOL(sound_install_audiodrv);
 
 int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
 	int driver_size, void *devc)
@@ -113,6 +144,7 @@
 	mixer_devs[n] = op;
 	return n;
 }
+EXPORT_SYMBOL(sound_install_mixer);
 
 void sound_unload_audiodev(int dev)
 {
@@ -122,6 +154,7 @@
 		unregister_sound_dsp((dev<<4)+3);
 	}
 }
+EXPORT_SYMBOL(sound_unload_audiodev);
 
 static int sound_alloc_audiodev(void)
 { 
@@ -144,6 +177,7 @@
 		num_midis = i + 1;
 	return i;
 }
+EXPORT_SYMBOL(sound_alloc_mididev);
 
 int sound_alloc_synthdev(void)
 {
@@ -158,6 +192,7 @@
 	}
 	return -1;
 }
+EXPORT_SYMBOL(sound_alloc_synthdev);
 
 int sound_alloc_mixerdev(void)
 {
@@ -169,6 +204,7 @@
 		num_mixers = i + 1;
 	return i;
 }
+EXPORT_SYMBOL(sound_alloc_mixerdev);
 
 int sound_alloc_timerdev(void)
 {
@@ -183,6 +219,7 @@
 	}
 	return -1;
 }
+EXPORT_SYMBOL(sound_alloc_timerdev);
 
 void sound_unload_mixerdev(int dev)
 {
@@ -192,6 +229,7 @@
 		num_mixers--;
 	}
 }
+EXPORT_SYMBOL(sound_unload_mixerdev);
 
 void sound_unload_mididev(int dev)
 {
@@ -200,15 +238,19 @@
 		unregister_sound_midi((dev<<4)+2);
 	}
 }
+EXPORT_SYMBOL(sound_unload_mididev);
 
 void sound_unload_synthdev(int dev)
 {
 	if (dev != -1)
 		synth_devs[dev] = NULL;
 }
+EXPORT_SYMBOL(sound_unload_synthdev);
 
 void sound_unload_timerdev(int dev)
 {
 	if (dev != -1)
 		sound_timer_devs[dev] = NULL;
 }
+EXPORT_SYMBOL(sound_unload_timerdev);
+
diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h
index adf1d62..b7617be 100644
--- a/sound/oss/dev_table.h
+++ b/sound/oss/dev_table.h
@@ -352,22 +352,8 @@
 	void (*arm_timer)(int dev, long time);
 };
 
-#ifdef _DEV_TABLE_C_   
-struct audio_operations *audio_devs[MAX_AUDIO_DEV];
-int num_audiodevs;
-struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
-int num_mixers;
-struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
-int num_synths;
-struct midi_operations *midi_devs[MAX_MIDI_DEV];
-int num_midis;
-
 extern struct sound_timer_operations default_sound_timer;
-struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
-	&default_sound_timer, NULL
-}; 
-int num_sound_timers = 1;
-#else
+
 extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
 extern int num_audiodevs;
 extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
@@ -378,7 +364,6 @@
 extern int num_midis;
 extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV];
 extern int num_sound_timers;
-#endif	/* _DEV_TABLE_C_ */
 
 extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
 void sound_timer_init (struct sound_lowlev_timer *t, char *name);
diff --git a/sound/oss/dm.h b/sound/oss/dm.h
deleted file mode 100644
index 14a9059..0000000
--- a/sound/oss/dm.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef _DRIVERS_SOUND_DM_H
-#define _DRIVERS_SOUND_DM_H
-
-/*
- *	Definitions of the 'direct midi sound' interface used
- *	by the newer commercial OSS package. We should export
- *	this to userland somewhere in glibc later.
- */
-
-/*
- * Data structure composing an FM "note" or sound event.
- */
-
-struct dm_fm_voice
-{
-	u8 op;
-	u8 voice;
-	u8 am;
-	u8 vibrato;
-	u8 do_sustain;
-	u8 kbd_scale;
-	u8 harmonic;
-	u8 scale_level;
-	u8 volume;
-	u8 attack;
-	u8 decay;
-	u8 sustain;
-	u8 release;
-	u8 feedback;
-	u8 connection;
-	u8 left;
-	u8 right;
-	u8 waveform;
-};
-
-/*
- *	This describes an FM note by its voice, octave, frequency number (10bit)
- *	and key on/off.
- */
-
-struct dm_fm_note
-{
-	u8 voice;
-	u8 octave;
-	u32 fnum;
-	u8 key_on;
-};
-
-/*
- * FM parameters that apply globally to all voices, and thus are not "notes"
- */
-
-struct dm_fm_params
-{
-	u8 am_depth;
-	u8 vib_depth;
-	u8 kbd_split;
-	u8 rhythm;
-
-	/* This block is the percussion instrument data */
-	u8 bass;
-	u8 snare;
-	u8 tomtom;
-	u8 cymbal;
-	u8 hihat;
-};
-
-/*
- *	FM mode ioctl settings
- */
- 
-#define FM_IOCTL_RESET        0x20
-#define FM_IOCTL_PLAY_NOTE    0x21
-#define FM_IOCTL_SET_VOICE    0x22
-#define FM_IOCTL_SET_PARAMS   0x23
-#define FM_IOCTL_SET_MODE     0x24
-#define FM_IOCTL_SET_OPL      0x25
-
-#endif
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index 6c1cf74..b256c04 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -926,6 +926,7 @@
 	sound_start_dma(dmap, physaddr, count, dma_mode);
 	return count;
 }
+EXPORT_SYMBOL(DMAbuf_start_dma);
 
 static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode)
 {
@@ -1055,6 +1056,8 @@
 		do_outputintr(dev, notify_only);
 	spin_unlock_irqrestore(&dmap->lock,flags);
 }
+EXPORT_SYMBOL(DMAbuf_outputintr);
+
 /* called with dmap->lock held in irq context */
 static void do_inputintr(int dev)
 {
@@ -1154,36 +1157,7 @@
 		do_inputintr(dev);
 	spin_unlock_irqrestore(&dmap->lock,flags);
 }
-
-int DMAbuf_open_dma(int dev)
-{
-	/*
-	 *    NOTE!  This routine opens only the primary DMA channel (output).
-	 */
-	struct audio_operations *adev = audio_devs[dev];
-	int err;
-
-	if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0)
-		return -EBUSY;
-	dma_init_buffers(adev->dmap_out);
-	adev->dmap_out->flags |= DMA_ALLOC_DONE;
-	adev->dmap_out->fragment_size = adev->dmap_out->buffsize;
-
-	if (adev->dmap_out->dma >= 0) {
-		unsigned long flags;
-
-		flags=claim_dma_lock();
-		clear_dma_ff(adev->dmap_out->dma);
-		disable_dma(adev->dmap_out->dma);
-		release_dma_lock(flags);
-	}
-	return 0;
-}
-
-void DMAbuf_close_dma(int dev)
-{
-	close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out);
-}
+EXPORT_SYMBOL(DMAbuf_inputintr);
 
 void DMAbuf_init(int dev, int dma1, int dma2)
 {
@@ -1192,12 +1166,6 @@
 	 * NOTE! This routine could be called several times.
 	 */
 
-	/* drag in audio_syms.o */
-	{
-		extern char audio_syms_symbol;
-		audio_syms_symbol = 0;
-	}
-
 	if (adev && adev->dmap_out == NULL) {
 		if (adev->d == NULL)
 			panic("OSS: audio_devs[%d]->d == NULL\n", dev);
diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
deleted file mode 100644
index 13f4831..0000000
--- a/sound/oss/es1370.c
+++ /dev/null
@@ -1,2819 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      es1370.c  --  Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
- *
- *      Copyright (C) 1998-2001, 2003  Thomas Sailer (t.sailer@alumni.ethz.ch)
- *
- *      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.
- *
- * Special thanks to David C. Niemi
- *
- *
- * Module command line parameters:
- *   lineout  if 1 the LINE jack is used as an output instead of an input.
- *            LINE then contains the unmixed dsp output. This can be used
- *            to make the card a four channel one: use dsp to output two
- *            channels to LINE and dac to output the other two channels to
- *            SPKR. Set the mixer to only output synth to SPKR.
- *   micbias  sets the +5V bias to the mic if using an electretmic.
- *            
- *
- *  Note: sync mode is not yet supported (i.e. running dsp and dac from the same
- *  clock source)
- *
- *  Supported devices:
- *  /dev/dsp    standard /dev/dsp device, (mostly) OSS compatible
- *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
- *  /dev/dsp1   additional DAC, like /dev/dsp, but output only,
- *              only 5512, 11025, 22050 and 44100 samples/s,
- *              outputs to mixer "SYNTH" setting
- *  /dev/midi   simple MIDI UART interface, no ioctl
- *
- *  NOTE: the card does not have any FM/Wavetable synthesizer, it is supposed
- *  to be done in software. That is what /dev/dac is for. By now (Q2 1998)
- *  there are several MIDI to PCM (WAV) packages, one of them is timidity.
- *
- *  Revision history
- *    26.03.1998   0.1   Initial release
- *    31.03.1998   0.2   Fix bug in GETOSPACE
- *    04.04.1998   0.3   Make it work (again) under 2.0.33
- *                       Fix mixer write operation not returning the actual
- *                       settings
- *    05.04.1998   0.4   First attempt at using the new PCI stuff
- *    29.04.1998   0.5   Fix hang when ^C is pressed on amp
- *    07.05.1998   0.6   Don't double lock around stop_*() in *_release()
- *    10.05.1998   0.7   First stab at a simple midi interface (no bells&whistles)
- *    14.05.1998   0.8   Don't allow excessive interrupt rates
- *    08.06.1998   0.9   First release using Alan Cox' soundcore instead of
- *                       miscdevice
- *    05.07.1998   0.10  Fixed the driver to correctly maintin OSS style volume
- *                       settings (not sure if this should be standard)
- *                       Fixed many references: f_flags should be f_mode
- *                       -- Gerald Britton <gbritton@mit.edu>
- *    03.08.1998   0.11  Now mixer behaviour can basically be selected between
- *                       "OSS documented" and "OSS actual" behaviour
- *                       Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se
- *                       On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
- *                       as it produces an annoying ssssh in the lower sampling rate
- *                       Do not include modversions.h
- *    22.08.1998   0.12  Mixer registers actually have 5 instead of 4 bits
- *                       pointed out by Itai Nahshon
- *    31.08.1998   0.13  Fix realplayer problems - dac.count issues
- *    08.10.1998   0.14  Joystick support fixed
- *		         -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
- *    10.12.1998   0.15  Fix drain_dac trying to wait on not yet initialized DMA
- *    16.12.1998   0.16  Don't wake up app until there are fragsize bytes to read/write
- *    06.01.1999   0.17  remove the silly SA_INTERRUPT flag.
- *                       hopefully killed the egcs section type conflict
- *    12.03.1999   0.18  cinfo.blocks should be reset after GETxPTR ioctl.
- *                       reported by Johan Maes <joma@telindus.be>
- *    22.03.1999   0.19  return EAGAIN instead of EBUSY when O_NONBLOCK
- *                       read/write cannot be executed
- *    07.04.1999   0.20  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
- *                       SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
- *                       Alpha fixes reported by Peter Jones <pjones@redhat.com>
- *                       Note: joystick address handling might still be wrong on archs
- *                       other than i386
- *    10.05.1999   0.21  Added support for an electret mic for SB PCI64
- *                       to the Linux kernel sound driver. This mod also straighten
- *                       out the question marks around the mic impedance setting
- *                       (micz). From Kim.Berts@fisub.mail.abb.com
- *    11.05.1999   0.22  Implemented the IMIX call to mute recording monitor.
- *                       Guenter Geiger <geiger@epy.co.at>
- *    15.06.1999   0.23  Fix bad allocation bug.
- *                       Thanks to Deti Fliegl <fliegl@in.tum.de>
- *    28.06.1999   0.24  Add pci_set_master
- *    02.08.1999   0.25  Added workaround for the "phantom write" bug first
- *                       documented by Dave Sharpless from Anchor Games
- *    03.08.1999   0.26  adapt to Linus' new __setup/__initcall
- *                       added kernel command line option "es1370=joystick[,lineout[,micbias]]"
- *                       removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
- *    12.08.1999   0.27  module_init/__setup fixes
- *    19.08.1999   0.28  SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
- *    31.08.1999   0.29  add spin_lock_init
- *                       replaced current->state = x with set_current_state(x)
- *    03.09.1999   0.30  change read semantics for MIDI to match
- *                       OSS more closely; remove possible wakeup race
- *    28.10.1999   0.31  More waitqueue races fixed
- *    08.01.2000   0.32  Prevent some ioctl's from returning bad count values on underrun/overrun;
- *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
- *    07.02.2000   0.33  Use pci_alloc_consistent and pci_register_driver
- *    21.11.2000   0.34  Initialize dma buffers in poll, otherwise poll may return a bogus mask
- *    12.12.2000   0.35  More dma buffer initializations, patch from
- *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- *    07.01.2001   0.36  Timeout change in wrcodec as requested by Frank Klemm <pfk@fuchs.offl.uni-jena.de>
- *    31.01.2001   0.37  Register/Unregister gameport
- *                       Fix SETTRIGGER non OSS API conformity
- *    03.01.2003   0.38  open_mode fixes from Georg Acher <acher@in.tum.de>
- *
- * some important things missing in Ensoniq documentation:
- *
- * Experimental PCLKDIV results:  play the same waveforms on both DAC1 and DAC2
- * and vary PCLKDIV to obtain zero beat.
- *  5512sps:  254
- * 44100sps:   30
- * seems to be fs = 1411200/(PCLKDIV+2)
- *
- * should find out when curr_sample_ct is cleared and
- * where exactly the CCB fetches data
- *
- * The card uses a 22.5792 MHz crystal.
- * The LINEIN jack may be converted to an AOUT jack by
- * setting pin 47 (XCTL0) of the ES1370 to high.
- * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic
- * 
- *
- */
-
-/*****************************************************************************/
-      
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/gameport.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#define DBG(x) {}
-/*#define DBG(x) {x}*/
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_ENSONIQ
-#define PCI_VENDOR_ID_ENSONIQ        0x1274    
-#endif
-
-#ifndef PCI_DEVICE_ID_ENSONIQ_ES1370
-#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
-#endif
-
-#define ES1370_MAGIC  ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1370)
-
-#define ES1370_EXTENT             0x40
-#define JOY_EXTENT                8
-
-#define ES1370_REG_CONTROL        0x00
-#define ES1370_REG_STATUS         0x04
-#define ES1370_REG_UART_DATA      0x08
-#define ES1370_REG_UART_STATUS    0x09
-#define ES1370_REG_UART_CONTROL   0x09
-#define ES1370_REG_UART_TEST      0x0a
-#define ES1370_REG_MEMPAGE        0x0c
-#define ES1370_REG_CODEC          0x10
-#define ES1370_REG_SERIAL_CONTROL 0x20
-#define ES1370_REG_DAC1_SCOUNT    0x24
-#define ES1370_REG_DAC2_SCOUNT    0x28
-#define ES1370_REG_ADC_SCOUNT     0x2c
-
-#define ES1370_REG_DAC1_FRAMEADR    0xc30
-#define ES1370_REG_DAC1_FRAMECNT    0xc34
-#define ES1370_REG_DAC2_FRAMEADR    0xc38
-#define ES1370_REG_DAC2_FRAMECNT    0xc3c
-#define ES1370_REG_ADC_FRAMEADR     0xd30
-#define ES1370_REG_ADC_FRAMECNT     0xd34
-#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
-#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
-
-#define ES1370_FMT_U8_MONO     0
-#define ES1370_FMT_U8_STEREO   1
-#define ES1370_FMT_S16_MONO    2
-#define ES1370_FMT_S16_STEREO  3
-#define ES1370_FMT_STEREO      1
-#define ES1370_FMT_S16         2
-#define ES1370_FMT_MASK        3
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
-
-#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
-#define DAC2_DIVTOSR(x) (1411200/((x)+2))
-
-#define CTRL_ADC_STOP   0x80000000  /* 1 = ADC stopped */
-#define CTRL_XCTL1      0x40000000  /* electret mic bias */
-#define CTRL_OPEN       0x20000000  /* no function, can be read and written */
-#define CTRL_PCLKDIV    0x1fff0000  /* ADC/DAC2 clock divider */
-#define CTRL_SH_PCLKDIV 16
-#define CTRL_MSFMTSEL   0x00008000  /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
-#define CTRL_M_SBB      0x00004000  /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
-#define CTRL_WTSRSEL    0x00003000  /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
-#define CTRL_SH_WTSRSEL 12
-#define CTRL_DAC_SYNC   0x00000800  /* 1 = DAC2 runs off DAC1 clock */
-#define CTRL_CCB_INTRM  0x00000400  /* 1 = CCB "voice" ints enabled */
-#define CTRL_M_CB       0x00000200  /* recording source: 0 = ADC, 1 = MPEG */
-#define CTRL_XCTL0      0x00000100  /* 0 = Line in, 1 = Line out */
-#define CTRL_BREQ       0x00000080  /* 1 = test mode (internal mem test) */
-#define CTRL_DAC1_EN    0x00000040  /* enable DAC1 */
-#define CTRL_DAC2_EN    0x00000020  /* enable DAC2 */
-#define CTRL_ADC_EN     0x00000010  /* enable ADC */
-#define CTRL_UART_EN    0x00000008  /* enable MIDI uart */
-#define CTRL_JYSTK_EN   0x00000004  /* enable Joystick port (presumably at address 0x200) */
-#define CTRL_CDC_EN     0x00000002  /* enable serial (CODEC) interface */
-#define CTRL_SERR_DIS   0x00000001  /* 1 = disable PCI SERR signal */
-
-#define STAT_INTR       0x80000000  /* wired or of all interrupt bits */
-#define STAT_CSTAT      0x00000400  /* 1 = codec busy or codec write in progress */
-#define STAT_CBUSY      0x00000200  /* 1 = codec busy */
-#define STAT_CWRIP      0x00000100  /* 1 = codec write in progress */
-#define STAT_VC         0x00000060  /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
-#define STAT_SH_VC      5
-#define STAT_MCCB       0x00000010  /* CCB int pending */
-#define STAT_UART       0x00000008  /* UART int pending */
-#define STAT_DAC1       0x00000004  /* DAC1 int pending */
-#define STAT_DAC2       0x00000002  /* DAC2 int pending */
-#define STAT_ADC        0x00000001  /* ADC int pending */
-
-#define USTAT_RXINT     0x80        /* UART rx int pending */
-#define USTAT_TXINT     0x04        /* UART tx int pending */
-#define USTAT_TXRDY     0x02        /* UART tx ready */
-#define USTAT_RXRDY     0x01        /* UART rx ready */
-
-#define UCTRL_RXINTEN   0x80        /* 1 = enable RX ints */
-#define UCTRL_TXINTEN   0x60        /* TX int enable field mask */
-#define UCTRL_ENA_TXINT 0x20        /* enable TX int */
-#define UCTRL_CNTRL     0x03        /* control field */
-#define UCTRL_CNTRL_SWR 0x03        /* software reset command */
-
-#define SCTRL_P2ENDINC    0x00380000  /*  */
-#define SCTRL_SH_P2ENDINC 19
-#define SCTRL_P2STINC     0x00070000  /*  */
-#define SCTRL_SH_P2STINC  16
-#define SCTRL_R1LOOPSEL   0x00008000  /* 0 = loop mode */
-#define SCTRL_P2LOOPSEL   0x00004000  /* 0 = loop mode */
-#define SCTRL_P1LOOPSEL   0x00002000  /* 0 = loop mode */
-#define SCTRL_P2PAUSE     0x00001000  /* 1 = pause mode */
-#define SCTRL_P1PAUSE     0x00000800  /* 1 = pause mode */
-#define SCTRL_R1INTEN     0x00000400  /* enable interrupt */
-#define SCTRL_P2INTEN     0x00000200  /* enable interrupt */
-#define SCTRL_P1INTEN     0x00000100  /* enable interrupt */
-#define SCTRL_P1SCTRLD    0x00000080  /* reload sample count register for DAC1 */
-#define SCTRL_P2DACSEN    0x00000040  /* 1 = DAC2 play back last sample when disabled */
-#define SCTRL_R1SEB       0x00000020  /* 1 = 16bit */
-#define SCTRL_R1SMB       0x00000010  /* 1 = stereo */
-#define SCTRL_R1FMT       0x00000030  /* format mask */
-#define SCTRL_SH_R1FMT    4
-#define SCTRL_P2SEB       0x00000008  /* 1 = 16bit */
-#define SCTRL_P2SMB       0x00000004  /* 1 = stereo */
-#define SCTRL_P2FMT       0x0000000c  /* format mask */
-#define SCTRL_SH_P2FMT    2
-#define SCTRL_P1SEB       0x00000002  /* 1 = 16bit */
-#define SCTRL_P1SMB       0x00000001  /* 1 = stereo */
-#define SCTRL_P1FMT       0x00000003  /* format mask */
-#define SCTRL_SH_P1FMT    0
-
-/* misc stuff */
-
-#define FMODE_DAC         4           /* slight misuse of mode_t */
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF  256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-/* --------------------------------------------------------------------- */
-
-struct es1370_state {
-	/* magic */
-	unsigned int magic;
-
-	/* list of es1370 devices */
-	struct list_head devs;
-
-	/* the corresponding pci_dev structure */
-	struct pci_dev *dev;
-
-	/* soundcore stuff */
-	int dev_audio;
-	int dev_mixer;
-	int dev_dac;
-	int dev_midi;
-	
-	/* hardware resources */
-	unsigned long io; /* long for SPARC */
-	unsigned int irq;
-
-	/* mixer registers; there is no HW readback */
-	struct {
-		unsigned short vol[10];
-		unsigned int recsrc;
-		unsigned int modcnt;
-		unsigned short micpreamp;
-	        unsigned int imix;
-	} mix;
-
-	/* wave stuff */
-	unsigned ctrl;
-	unsigned sctrl;
-
-	spinlock_t lock;
-	struct mutex open_mutex;
-	mode_t open_mode;
-	wait_queue_head_t open_wait;
-
-	struct dmabuf {
-		void *rawbuf;
-		dma_addr_t dmaaddr;
-		unsigned buforder;
-		unsigned numfrag;
-		unsigned fragshift;
-		unsigned hwptr, swptr;
-		unsigned total_bytes;
-		int count;
-		unsigned error; /* over/underrun */
-		wait_queue_head_t wait;
-		/* redundant, but makes calculations easier */
-		unsigned fragsize;
-		unsigned dmasize;
-		unsigned fragsamples;
-		/* OSS stuff */
-		unsigned mapped:1;
-		unsigned ready:1;
-		unsigned endcleared:1;
-		unsigned enabled:1;
-		unsigned ossfragshift;
-		int ossmaxfrags;
-		unsigned subdivision;
-	} dma_dac1, dma_dac2, dma_adc;
-
-	/* The following buffer is used to point the phantom write channel to. */
-	unsigned char *bugbuf_cpu;
-	dma_addr_t bugbuf_dma;
-
-	/* midi stuff */
-	struct {
-		unsigned ird, iwr, icnt;
-		unsigned ord, owr, ocnt;
-		wait_queue_head_t iwait;
-		wait_queue_head_t owait;
-		unsigned char ibuf[MIDIINBUF];
-		unsigned char obuf[MIDIOUTBUF];
-	} midi;
-
-#ifdef SUPPORT_JOYSTICK
-	struct gameport *gameport;
-#endif
-
-	struct mutex mutex;
-};
-
-/* --------------------------------------------------------------------- */
-
-static LIST_HEAD(devs);
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data)
-{
-	unsigned long tmo = jiffies + HZ/10, j;
-	
-	do {
-		j = jiffies;
-		if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) {
-			outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC);
-			return;
-		}
-		schedule();
-	} while ((signed)(tmo-j) > 0);
-	printk(KERN_ERR "es1370: write to codec register timeout\n");
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct es1370_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->ctrl &= ~CTRL_ADC_EN;
-	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static inline void stop_dac1(struct es1370_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->ctrl &= ~CTRL_DAC1_EN;
-	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static inline void stop_dac2(struct es1370_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->ctrl &= ~CTRL_DAC2_EN;
-	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static void start_dac1(struct es1370_state *s)
-{
-	unsigned long flags;
-	unsigned fragremain, fshift;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0)
-	    && s->dma_dac1.ready) {
-		s->ctrl |= CTRL_DAC1_EN;
-		s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN;
-		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-		fragremain = ((- s->dma_dac1.hwptr) & (s->dma_dac1.fragsize-1));
-		fshift = sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		if (fragremain < 2*fshift)
-			fragremain = s->dma_dac1.fragsize;
-		outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT);
-		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-		outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static void start_dac2(struct es1370_state *s)
-{
-	unsigned long flags;
-	unsigned fragremain, fshift;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->ctrl & CTRL_DAC2_EN) && (s->dma_dac2.mapped || s->dma_dac2.count > 0)
-	    && s->dma_dac2.ready) {
-		s->ctrl |= CTRL_DAC2_EN;
-		s->sctrl = (s->sctrl & ~(SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN | 
-					 SCTRL_P2ENDINC | SCTRL_P2STINC)) | SCTRL_P2INTEN |
-			(((s->sctrl & SCTRL_P2FMT) ? 2 : 1) << SCTRL_SH_P2ENDINC) | 
-			(0 << SCTRL_SH_P2STINC);
-		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-		fragremain = ((- s->dma_dac2.hwptr) & (s->dma_dac2.fragsize-1));
-		fshift = sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		if (fragremain < 2*fshift)
-			fragremain = s->dma_dac2.fragsize;
-		outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT);
-		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-		outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static void start_adc(struct es1370_state *s)
-{
-	unsigned long flags;
-	unsigned fragremain, fshift;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
-	    && s->dma_adc.ready) {
-		s->ctrl |= CTRL_ADC_EN;
-		s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN;
-		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-		fragremain = ((- s->dma_adc.hwptr) & (s->dma_adc.fragsize-1));
-		fshift = sample_shift[(s->sctrl & SCTRL_R1FMT) >> SCTRL_SH_R1FMT];
-		if (fragremain < 2*fshift)
-			fragremain = s->dma_adc.fragsize;
-		outl((fragremain >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT);
-		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-		outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct es1370_state *s, struct dmabuf *db)
-{
-	struct page *page, *pend;
-
-	if (db->rawbuf) {
-		/* undo marking the pages as reserved */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			ClearPageReserved(page);
-		pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
-	}
-	db->rawbuf = NULL;
-	db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct es1370_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg)
-{
-	int order;
-	unsigned bytepersec;
-	unsigned bufs;
-	struct page *page, *pend;
-
-	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-			if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
-				break;
-		if (!db->rawbuf)
-			return -ENOMEM;
-		db->buforder = order;
-		/* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			SetPageReserved(page);
-	}
-	fmt &= ES1370_FMT_MASK;
-	bytepersec = rate << sample_shift[fmt];
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytepersec)
-			db->fragshift = ld2(bytepersec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-	db->fragsamples = db->fragsize >> sample_shift[fmt];
-	db->dmasize = db->numfrag << db->fragshift;
-	memset(db->rawbuf, (fmt & ES1370_FMT_S16) ? 0 : 0x80, db->dmasize);
-	outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
-	outl(db->dmaaddr, s->io+(reg & 0xff));
-	outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff));
-	db->enabled = 1;
-	db->ready = 1;
-	return 0;
-}
-
-static inline int prog_dmabuf_adc(struct es1370_state *s)
-{
-	stop_adc(s);
-	return prog_dmabuf(s, &s->dma_adc, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
-			   (s->sctrl >> SCTRL_SH_R1FMT) & ES1370_FMT_MASK, ES1370_REG_ADC_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac2(struct es1370_state *s)
-{
-	stop_dac2(s);
-	return prog_dmabuf(s, &s->dma_dac2, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
-			   (s->sctrl >> SCTRL_SH_P2FMT) & ES1370_FMT_MASK, ES1370_REG_DAC2_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac1(struct es1370_state *s)
-{
-	stop_dac1(s);
-	return prog_dmabuf(s, &s->dma_dac1, dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
-			   (s->sctrl >> SCTRL_SH_P1FMT) & ES1370_FMT_MASK, ES1370_REG_DAC1_FRAMEADR);
-}
-
-static inline unsigned get_hwptr(struct es1370_state *s, struct dmabuf *db, unsigned reg)
-{
-	unsigned hwptr, diff;
-
-	outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
-	hwptr = (inl(s->io+(reg & 0xff)) >> 14) & 0x3fffc;
-	diff = (db->dmasize + hwptr - db->hwptr) % db->dmasize;
-	db->hwptr = hwptr;
-	return diff;
-}
-
-static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
-{
-	if (bptr + len > bsize) {
-		unsigned x = bsize - bptr;
-		memset(((char *)buf) + bptr, c, x);
-		bptr = 0;
-		len -= x;
-	}
-	memset(((char *)buf) + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void es1370_update_ptr(struct es1370_state *s)
-{
-	int diff;
-
-	/* update ADC pointer */
-	if (s->ctrl & CTRL_ADC_EN) {
-		diff = get_hwptr(s, &s->dma_adc, ES1370_REG_ADC_FRAMECNT);
-		s->dma_adc.total_bytes += diff;
-		s->dma_adc.count += diff;
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
-			wake_up(&s->dma_adc.wait);
-		if (!s->dma_adc.mapped) {
-			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-				s->ctrl &= ~CTRL_ADC_EN;
-				outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-				s->dma_adc.error++;
-			}
-		}
-	}
-	/* update DAC1 pointer */
-	if (s->ctrl & CTRL_DAC1_EN) {
-		diff = get_hwptr(s, &s->dma_dac1, ES1370_REG_DAC1_FRAMECNT);
-		s->dma_dac1.total_bytes += diff;
-		if (s->dma_dac1.mapped) {
-			s->dma_dac1.count += diff;
-			if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
-				wake_up(&s->dma_dac1.wait);
-		} else {
-			s->dma_dac1.count -= diff;
-			if (s->dma_dac1.count <= 0) {
-				s->ctrl &= ~CTRL_DAC1_EN;
-				outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-				s->dma_dac1.error++;
-			} else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) {
-				clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr, 
-					      s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80);
-				s->dma_dac1.endcleared = 1;
-			}
-			if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize)
-				wake_up(&s->dma_dac1.wait);
-		}
-	}
-	/* update DAC2 pointer */
-	if (s->ctrl & CTRL_DAC2_EN) {
-		diff = get_hwptr(s, &s->dma_dac2, ES1370_REG_DAC2_FRAMECNT);
-		s->dma_dac2.total_bytes += diff;
-		if (s->dma_dac2.mapped) {
-			s->dma_dac2.count += diff;
-			if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize)
-				wake_up(&s->dma_dac2.wait);
-		} else {
-			s->dma_dac2.count -= diff;
-			if (s->dma_dac2.count <= 0) {
-				s->ctrl &= ~CTRL_DAC2_EN;
-				outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-				s->dma_dac2.error++;
-			} else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) {
-				clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr, 
-					      s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80);
-				s->dma_dac2.endcleared = 1;
-			}
-			if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize)
-				wake_up(&s->dma_dac2.wait);
-		}
-	}
-}
-
-/* hold spinlock for the following! */
-static void es1370_handle_midi(struct es1370_state *s)
-{
-	unsigned char ch;
-	int wake;
-
-	if (!(s->ctrl & CTRL_UART_EN))
-		return;
-	wake = 0;
-	while (inb(s->io+ES1370_REG_UART_STATUS) & USTAT_RXRDY) {
-		ch = inb(s->io+ES1370_REG_UART_DATA);
-		if (s->midi.icnt < MIDIINBUF) {
-			s->midi.ibuf[s->midi.iwr] = ch;
-			s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
-			s->midi.icnt++;
-		}
-		wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.iwait);
-	wake = 0;
-	while ((inb(s->io+ES1370_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) {
-		outb(s->midi.obuf[s->midi.ord], s->io+ES1370_REG_UART_DATA);
-		s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
-		s->midi.ocnt--;
-		if (s->midi.ocnt < MIDIOUTBUF-16)
-			wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.owait);
-	outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1370_REG_UART_CONTROL);
-}
-
-static irqreturn_t es1370_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct es1370_state *s = (struct es1370_state *)dev_id;
-	unsigned int intsrc, sctl;
-	
-	/* fastpath out, to ease interrupt sharing */
-	intsrc = inl(s->io+ES1370_REG_STATUS);
-	if (!(intsrc & 0x80000000))
-		return IRQ_NONE;
-	spin_lock(&s->lock);
-	/* clear audio interrupts first */
-	sctl = s->sctrl;
-	if (intsrc & STAT_ADC)
-		sctl &= ~SCTRL_R1INTEN;
-	if (intsrc & STAT_DAC1)
-		sctl &= ~SCTRL_P1INTEN;
-	if (intsrc & STAT_DAC2)
-		sctl &= ~SCTRL_P2INTEN;
-	outl(sctl, s->io+ES1370_REG_SERIAL_CONTROL);
-	outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-	es1370_update_ptr(s);
-	es1370_handle_midi(s);
-	spin_unlock(&s->lock);
-	return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "es1370: invalid magic value\n";
-
-#define VALIDATE_STATE(s)                         \
-({                                                \
-	if (!(s) || (s)->magic != ES1370_MAGIC) { \
-		printk(invalid_magic);            \
-		return -ENXIO;                    \
-	}                                         \
-})
-
-/* --------------------------------------------------------------------- */
-
-static const struct {
-	unsigned volidx:4;
-	unsigned left:4;
-	unsigned right:4;
-	unsigned stereo:1;
-	unsigned recmask:13;
-	unsigned avail:1;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
-	[SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x0000, 1 },   /* master */
-	[SOUND_MIXER_PCM]    = { 1, 0x2, 0x3, 1, 0x0400, 1 },   /* voice */
-	[SOUND_MIXER_SYNTH]  = { 2, 0x4, 0x5, 1, 0x0060, 1 },   /* FM */
-	[SOUND_MIXER_CD]     = { 3, 0x6, 0x7, 1, 0x0006, 1 },   /* CD */
-	[SOUND_MIXER_LINE]   = { 4, 0x8, 0x9, 1, 0x0018, 1 },   /* Line */
-	[SOUND_MIXER_LINE1]  = { 5, 0xa, 0xb, 1, 0x1800, 1 },   /* AUX */
-	[SOUND_MIXER_LINE2]  = { 6, 0xc, 0x0, 0, 0x0100, 1 },   /* Mono1 */
-	[SOUND_MIXER_LINE3]  = { 7, 0xd, 0x0, 0, 0x0200, 1 },   /* Mono2 */
-	[SOUND_MIXER_MIC]    = { 8, 0xe, 0x0, 0, 0x0001, 1 },   /* Mic */
-	[SOUND_MIXER_OGAIN]  = { 9, 0xf, 0x0, 0, 0x0000, 1 }    /* mono out */
-};
-
-static void set_recsrc(struct es1370_state *s, unsigned int val)
-{
-	unsigned int i, j;
-
-	for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-		if (!(val & (1 << i)))
-			continue;
-		if (!mixtable[i].recmask) {
-			val &= ~(1 << i);
-			continue;
-		}
-		j |= mixtable[i].recmask;
-	}
-	s->mix.recsrc = val;
-	wrcodec(s, 0x12, j & 0xd5);
-	wrcodec(s, 0x13, j & 0xaa);
-	wrcodec(s, 0x14, (j >> 8) & 0x17);
-	wrcodec(s, 0x15, (j >> 8) & 0x0f);
-	i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
-	if (!s->mix.imix) {
-		i &= 0xff60;  /* mute record and line monitor */
-	}
-	wrcodec(s, 0x10, i);
-	wrcodec(s, 0x11, i >> 8);
-}
-
-static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg)
-{
-	unsigned long flags;
-	int i, val;
-	unsigned char l, r, rl, rr;
-	int __user *p = (int __user *)arg;
-
-	VALIDATE_STATE(s);
-	if (cmd == SOUND_MIXER_PRIVATE1) {
-		/* enable/disable/query mixer preamp */
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != -1) {
-			s->mix.micpreamp = !!val;
-			wrcodec(s, 0x19, s->mix.micpreamp);
-		}
-		return put_user(s->mix.micpreamp, p);
-	}
-	if (cmd == SOUND_MIXER_PRIVATE2) {
-		/* enable/disable/query use of linein as second lineout */
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != -1) {
-			spin_lock_irqsave(&s->lock, flags);
-			if (val)
-				s->ctrl |= CTRL_XCTL0;
-			else
-				s->ctrl &= ~CTRL_XCTL0;
-			outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		return put_user((s->ctrl & CTRL_XCTL0) ? 1 : 0, p);
-	}
-	if (cmd == SOUND_MIXER_PRIVATE3) {
-		/* enable/disable/query microphone impedance setting */
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != -1) {
-			spin_lock_irqsave(&s->lock, flags);
-			if (val)
-				s->ctrl |= CTRL_XCTL1;
-			else
-				s->ctrl &= ~CTRL_XCTL1;
-			outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		return put_user((s->ctrl & CTRL_XCTL1) ? 1 : 0, p);
-	}
-        if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		strncpy(info.id, "ES1370", sizeof(info.id));
-		strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
-		info.modify_counter = s->mix.modcnt;
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		strncpy(info.id, "ES1370", sizeof(info.id));
-		strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, p);
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
-        if (_SIOC_DIR(cmd) == _SIOC_READ) {
-                switch (_IOC_NR(cmd)) {
-                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			return put_user(s->mix.recsrc, p);
-			
-                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-			val = SOUND_MASK_IMIX;
-			for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].avail)
-					val |= 1 << i;
-			return put_user(val, p);
-
-                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].recmask)
-					val |= 1 << i;
-			return put_user(val, p);
-			
-                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].stereo)
-					val |= 1 << i;
-			return put_user(val, p);
-			
-                case SOUND_MIXER_CAPS:
-			return put_user(0, p);
-		
-		case SOUND_MIXER_IMIX:
-			return put_user(s->mix.imix, p);
-
-		default:
-			i = _IOC_NR(cmd);
-                        if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
-                                return -EINVAL;
-			return put_user(s->mix.vol[mixtable[i].volidx], p);
-		}
-	}
-        if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) 
-		return -EINVAL;
-	s->mix.modcnt++;
-	switch (_IOC_NR(cmd)) {
-
-	case SOUND_MIXER_IMIX:
-		if (get_user(s->mix.imix, p))
-			return -EFAULT;
-		set_recsrc(s, s->mix.recsrc);
-		return 0;
-
-	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-		if (get_user(val, p))
-			return -EFAULT;
-		set_recsrc(s, val);
-		return 0;
-
-	default:
-		i = _IOC_NR(cmd);
-		if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
-			return -EINVAL;
-		if (get_user(val, p))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		if (mixtable[i].stereo) {
-			r = (val >> 8) & 0xff;
-			if (r > 100)
-				r = 100;
-			if (l < 7) {
-				rl = 0x80;
-				l = 0;
-			} else {
-				rl = 31 - ((l - 7) / 3);
-				l = (31 - rl) * 3 + 7;
-			}
-			if (r < 7) {
-				rr = 0x80;
-				r = 0;
-			} else {
-				rr =  31 - ((r - 7) / 3);
-				r = (31 - rr) * 3 + 7;
-			}
-			wrcodec(s, mixtable[i].right, rr);
-		} else { 
-			if (mixtable[i].left == 15) {
-				if (l < 2) {
-					rr = rl = 0x80;
-					r = l = 0;
-				} else {
-					rl = 7 - ((l - 2) / 14);
-					r = l = (7 - rl) * 14 + 2;
-				}
-			} else {
-				if (l < 7) {
-					rl = 0x80;
-					r = l = 0;
-				} else {
-					rl = 31 - ((l - 7) / 3);
-					r = l = (31 - rl) * 3 + 7;
-				}
-			}
-		}
-		wrcodec(s, mixtable[i].left, rl);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		s->mix.vol[mixtable[i].volidx] = ((unsigned int)r << 8) | l;
-#else
-		s->mix.vol[mixtable[i].volidx] = val;
-#endif
-                return put_user(s->mix.vol[mixtable[i].volidx], p);
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-static int es1370_open_mixdev(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct list_head *list;
-	struct es1370_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct es1370_state, devs);
-		if (s->dev_mixer == minor)
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	return nonseekable_open(inode, file);
-}
-
-static int es1370_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	
-	VALIDATE_STATE(s);
-	return 0;
-}
-
-static int es1370_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	return mixer_ioctl((struct es1370_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations es1370_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= es1370_ioctl_mixdev,
-	.open		= es1370_open_mixdev,
-	.release	= es1370_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac1(struct es1370_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count, tmo;
-	
-	if (s->dma_dac1.mapped || !s->dma_dac1.ready)
-		return 0;
-        add_wait_queue(&s->dma_dac1.wait, &wait);
-        for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-                spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac1.count;
-                spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-                        break;
-                if (nonblock) {
-                        remove_wait_queue(&s->dma_dac1.wait, &wait);
-                        set_current_state(TASK_RUNNING);
-                        return -EBUSY;
-                }
-		tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
-			/ dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
-		tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
-		if (!schedule_timeout(tmo + 1))
-			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
-        }
-        remove_wait_queue(&s->dma_dac1.wait, &wait);
-        set_current_state(TASK_RUNNING);
-        if (signal_pending(current))
-                return -ERESTARTSYS;
-        return 0;
-}
-
-static int drain_dac2(struct es1370_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count, tmo;
-
-	if (s->dma_dac2.mapped || !s->dma_dac2.ready)
-		return 0;
-        add_wait_queue(&s->dma_dac2.wait, &wait);
-        for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-                spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac2.count;
-                spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-                        break;
-                if (nonblock) {
-                        remove_wait_queue(&s->dma_dac2.wait, &wait);
-                        set_current_state(TASK_RUNNING);
-                        return -EBUSY;
-                }
-		tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
-			/ DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
-		tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
-		if (!schedule_timeout(tmo + 1))
-			DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
-        }
-        remove_wait_queue(&s->dma_dac2.wait, &wait);
-        set_current_state(TASK_RUNNING);
-        if (signal_pending(current))
-                return -ERESTARTSYS;
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret = 0;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_adc.mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	mutex_lock(&s->mutex);
-	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-		goto out;
-        
-	add_wait_queue(&s->dma_adc.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		swptr = s->dma_adc.swptr;
-		cnt = s->dma_adc.dmasize-swptr;
-		if (s->dma_adc.count < cnt)
-			cnt = s->dma_adc.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (s->dma_adc.enabled)
-				start_adc(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				goto out;
-			}
-			mutex_unlock(&s->mutex);
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				goto out;
-			}
-			mutex_lock(&s->mutex);
-			if (s->dma_adc.mapped)
-			{
-				ret = -ENXIO;
-				goto out;
-			}
-			continue;
-		}
-		if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-		swptr = (swptr + cnt) % s->dma_adc.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_adc.swptr = swptr;
-		s->dma_adc.count -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_adc.enabled)
-			start_adc(s);
-	}
-out:
-	mutex_unlock(&s->mutex);
-        remove_wait_queue(&s->dma_adc.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static ssize_t es1370_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret = 0;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_dac2.mapped)
-		return -ENXIO;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	mutex_lock(&s->mutex);
-	if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-		goto out;
-	ret = 0;
-        add_wait_queue(&s->dma_dac2.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		if (s->dma_dac2.count < 0) {
-			s->dma_dac2.count = 0;
-			s->dma_dac2.swptr = s->dma_dac2.hwptr;
-		}
-		swptr = s->dma_dac2.swptr;
-		cnt = s->dma_dac2.dmasize-swptr;
-		if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize)
-			cnt = s->dma_dac2.dmasize - s->dma_dac2.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (s->dma_dac2.enabled)
-				start_dac2(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				goto out;
-			}
-			mutex_unlock(&s->mutex);
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				goto out;	
-			}
-			mutex_lock(&s->mutex);
-			if (s->dma_dac2.mapped)
-			{
-			ret = -ENXIO;
-			goto out;
-			}
-			continue;
-		}
-		if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			goto out;
-		}
-		swptr = (swptr + cnt) % s->dma_dac2.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_dac2.swptr = swptr;
-		s->dma_dac2.count += cnt;
-		s->dma_dac2.endcleared = 0;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_dac2.enabled)
-			start_dac2(s);
-	}
-out:
-	mutex_unlock(&s->mutex);
-        remove_wait_queue(&s->dma_dac2.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac2.ready && prog_dmabuf_dac2(s))
-			return 0;
-		poll_wait(file, &s->dma_dac2.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready && prog_dmabuf_adc(s))
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	es1370_update_ptr(s);
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac2.mapped) {
-			if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) 
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int es1370_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	struct dmabuf *db;
-	int ret = 0;
-	unsigned long size;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	mutex_lock(&s->mutex);
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf_dac2(s)) != 0) {
-			goto out;
-		}
-		db = &s->dma_dac2;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf_adc(s)) != 0) {
-			goto out;
-		}
-		db = &s->dma_adc;
-	} else  {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (vma->vm_pgoff != 0) {
-		ret = -EINVAL;
-		goto out;
-	}
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder)) {
-		ret = -EINVAL;
-		goto out;
-	}
-	if (remap_pfn_range(vma, vma->vm_start,
-				virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
-				size, vma->vm_page_prot)) {
-		ret = -EAGAIN;
-		goto out;
-	}
-	db->mapped = 1;
-out:
-	mutex_unlock(&s->mutex);
-	unlock_kernel();
-	return ret;
-}
-
-static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
-	int count;
-	int val, mapped, ret;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	VALIDATE_STATE(s);
-        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
-		return 0;
-		
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-		
-        case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac2(s);
-			synchronize_irq(s->irq);
-			s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq(s->irq);
-			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SPEED:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-			if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
-				return -EINVAL;
-			if (val < 4000)
-				val = 4000;
-			if (val > 50000)
-				val = 50000;
-			stop_adc(s);
-			stop_dac2(s);
-			s->dma_adc.ready = s->dma_dac2.ready = 0;
-			spin_lock_irqsave(&s->lock, flags);
-			s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV);
-			outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p);
-		
-        case SNDCTL_DSP_STEREO:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ready = 0;
-			spin_lock_irqsave(&s->lock, flags);
-			if (val)
-				s->sctrl |= SCTRL_R1SMB;
-			else
-				s->sctrl &= ~SCTRL_R1SMB;
-			outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac2(s);
-			s->dma_dac2.ready = 0;
-			spin_lock_irqsave(&s->lock, flags);
-			if (val)
-				s->sctrl |= SCTRL_P2SMB;
-			else
-				s->sctrl &= ~SCTRL_P2SMB;
-			outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-                }
-		return 0;
-
-        case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				spin_lock_irqsave(&s->lock, flags);
-				if (val >= 2)
-					s->sctrl |= SCTRL_R1SMB;
-				else
-					s->sctrl &= ~SCTRL_R1SMB;
-				outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac2(s);
-				s->dma_dac2.ready = 0;
-				spin_lock_irqsave(&s->lock, flags);
-				if (val >= 2)
-					s->sctrl |= SCTRL_P2SMB;
-				else
-					s->sctrl &= ~SCTRL_P2SMB;
-				outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-		}
-		return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p);
-		
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_LE|AFMT_U8, p);
-		
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				spin_lock_irqsave(&s->lock, flags);
-				if (val == AFMT_S16_LE)
-					s->sctrl |= SCTRL_R1SEB;
-				else
-					s->sctrl &= ~SCTRL_R1SEB;
-				outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac2(s);
-				s->dma_dac2.ready = 0;
-				spin_lock_irqsave(&s->lock, flags);
-				if (val == AFMT_S16_LE)
-					s->sctrl |= SCTRL_P2SEB;
-				else
-					s->sctrl &= ~SCTRL_P2SEB;
-				outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-		}
-		return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? 
-				AFMT_S16_LE : AFMT_U8, p);
-		
-	case SNDCTL_DSP_POST:
-                return 0;
-
-        case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN) 
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN) 
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, p);
-		
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-					return ret;
-				s->dma_adc.enabled = 1;
-				start_adc(s);
-			} else {
-				s->dma_adc.enabled = 0;
-				stop_adc(s);
-			}
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-					return ret;
-				s->dma_dac2.enabled = 1;
-				start_dac2(s);
-			} else {
-				s->dma_dac2.enabled = 0;
-				stop_dac2(s);
-			}
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-		abinfo.fragsize = s->dma_dac2.fragsize;
-		count = s->dma_dac2.count;
-		if (count < 0)
-			count = 0;
-                abinfo.bytes = s->dma_dac2.dmasize - count;
-                abinfo.fragstotal = s->dma_dac2.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-		abinfo.fragsize = s->dma_adc.fragsize;
-		count = s->dma_adc.count;
-		if (count < 0)
-			count = 0;
-                abinfo.bytes = count;
-                abinfo.fragstotal = s->dma_adc.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-		
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-                count = s->dma_dac2.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		return put_user(count, p);
-
-        case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-                cinfo.bytes = s->dma_adc.total_bytes;
-		count = s->dma_adc.count;
-		if (count < 0)
-			count = 0;
-                cinfo.blocks = count >> s->dma_adc.fragshift;
-                cinfo.ptr = s->dma_adc.hwptr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= s->dma_adc.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-                cinfo.bytes = s->dma_dac2.total_bytes;
-		count = s->dma_dac2.count;
-		if (count < 0)
-			count = 0;
-                cinfo.blocks = count >> s->dma_dac2.fragshift;
-                cinfo.ptr = s->dma_dac2.hwptr;
-		if (s->dma_dac2.mapped)
-			s->dma_dac2.count &= s->dma_dac2.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf_dac2(s)))
-				return val;
-			return put_user(s->dma_dac2.fragsize, p);
-		}
-		if ((val = prog_dmabuf_adc(s)))
-			return val;
-		return put_user(s->dma_adc.fragsize, p);
-
-        case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			s->dma_dac2.ossfragshift = val & 0xffff;
-			s->dma_dac2.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac2.ossfragshift < 4)
-				s->dma_dac2.ossfragshift = 4;
-			if (s->dma_dac2.ossfragshift > 15)
-				s->dma_dac2.ossfragshift = 15;
-			if (s->dma_dac2.ossmaxfrags < 4)
-				s->dma_dac2.ossmaxfrags = 4;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
-			return -EINVAL;
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			s->dma_dac2.subdivision = val;
-		return 0;
-
-        case SOUND_PCM_READ_RATE:
-		return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p);
-
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ?
-				2 : 1, p);
-
-        case SOUND_PCM_READ_BITS:
-		return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ? 
-				16 : 8, p);
-
-        case SOUND_PCM_WRITE_FILTER:
-        case SNDCTL_DSP_SETSYNCRO:
-        case SOUND_PCM_READ_FILTER:
-                return -EINVAL;
-		
-	}
-	return mixer_ioctl(s, cmd, arg);
-}
-
-static int es1370_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	struct list_head *list;
-	struct es1370_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct es1370_state, devs);
-		if (!((s->dev_audio ^ minor) & ~0xf))
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & file->f_mode) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_READ|FMODE_WRITE)))
-		s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV);
-	if (file->f_mode & FMODE_READ) {
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
-		s->dma_adc.enabled = 1;
-		s->sctrl &= ~SCTRL_R1FMT;
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT;
-		else
-			s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_R1FMT;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0;
-		s->dma_dac2.enabled = 1;
-		s->sctrl &= ~SCTRL_P2FMT;
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT;
-		else
-			s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P2FMT;
-	}
-	outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_unlock(&s->open_mutex);
-	mutex_init(&s->mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int es1370_release(struct inode *inode, struct file *file)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE)
-		drain_dac2(s, file->f_flags & O_NONBLOCK);
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac2(s);
-		synchronize_irq(s->irq);
-		dealloc_dmabuf(s, &s->dma_dac2);
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-		dealloc_dmabuf(s, &s->dma_adc);
-	}
-	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations es1370_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= es1370_read,
-	.write		= es1370_write,
-	.poll		= es1370_poll,
-	.ioctl		= es1370_ioctl,
-	.mmap		= es1370_mmap,
-	.open		= es1370_open,
-	.release	= es1370_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret = 0;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_dac1.mapped)
-		return -ENXIO;
-	if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-        add_wait_queue(&s->dma_dac1.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		if (s->dma_dac1.count < 0) {
-			s->dma_dac1.count = 0;
-			s->dma_dac1.swptr = s->dma_dac1.hwptr;
-		}
-		swptr = s->dma_dac1.swptr;
-		cnt = s->dma_dac1.dmasize-swptr;
-		if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize)
-			cnt = s->dma_dac1.dmasize - s->dma_dac1.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (s->dma_dac1.enabled)
-				start_dac1(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		swptr = (swptr + cnt) % s->dma_dac1.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_dac1.swptr = swptr;
-		s->dma_dac1.count += cnt;
-		s->dma_dac1.endcleared = 0;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_dac1.enabled)
-			start_dac1(s);
-	}
-        remove_wait_queue(&s->dma_dac1.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1370_poll_dac(struct file *file, struct poll_table_struct *wait)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (!s->dma_dac1.ready && prog_dmabuf_dac1(s))
-		return 0;
-	poll_wait(file, &s->dma_dac1.wait, wait);
-	spin_lock_irqsave(&s->lock, flags);
-	es1370_update_ptr(s);
-	if (s->dma_dac1.mapped) {
-		if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
-			mask |= POLLOUT | POLLWRNORM;
-	} else {
-		if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize)
-			mask |= POLLOUT | POLLWRNORM;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int es1370_mmap_dac(struct file *file, struct vm_area_struct *vma)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	int ret;
-	unsigned long size;
-
-	VALIDATE_STATE(s);
-	if (!(vma->vm_flags & VM_WRITE))
-		return -EINVAL;
-	lock_kernel();
-	if ((ret = prog_dmabuf_dac1(s)) != 0)
-		goto out;
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << s->dma_dac1.buforder))
-		goto out;
-	ret = -EAGAIN;
-	if (remap_pfn_range(vma, vma->vm_start,
-			virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT,
-			size, vma->vm_page_prot))
-		goto out;
-	s->dma_dac1.mapped = 1;
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
-	int count;
-	unsigned ctrl;
-	int val, ret;
-	int __user *p = (int __user *)arg;
-
-	VALIDATE_STATE(s);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-		return drain_dac1(s, 0/*file->f_flags & O_NONBLOCK*/);
-		
-	case SNDCTL_DSP_SETDUPLEX:
-		return -EINVAL;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-		
-        case SNDCTL_DSP_RESET:
-		stop_dac1(s);
-		synchronize_irq(s->irq);
-		s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0;
-		return 0;
-
-        case SNDCTL_DSP_SPEED:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-			stop_dac1(s);
-			s->dma_dac1.ready = 0;
-			for (ctrl = 0; ctrl <= 2; ctrl++)
-				if (val < (dac1_samplerate[ctrl] + dac1_samplerate[ctrl+1]) / 2)
-					break;
-			spin_lock_irqsave(&s->lock, flags);
-			s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (ctrl << CTRL_SH_WTSRSEL);
-			outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p);
-		
-        case SNDCTL_DSP_STEREO:
-                if (get_user(val, p))
-			return -EFAULT;
-		stop_dac1(s);
-		s->dma_dac1.ready = 0;
-		spin_lock_irqsave(&s->lock, flags);
-		if (val)
-			s->sctrl |= SCTRL_P1SMB;
-		else
-			s->sctrl &= ~SCTRL_P1SMB;
-		outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-		spin_unlock_irqrestore(&s->lock, flags);
-		return 0;
-
-        case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 0) {
-			if (s->dma_dac1.mapped)
-				return -EINVAL;
-			stop_dac1(s);
-			s->dma_dac1.ready = 0;
-			spin_lock_irqsave(&s->lock, flags);
-			if (val >= 2)
-				s->sctrl |= SCTRL_P1SMB;
-			else
-				s->sctrl &= ~SCTRL_P1SMB;
-			outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
-		
-        case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_LE|AFMT_U8, p);
-		
-        case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			stop_dac1(s);
-			s->dma_dac1.ready = 0;
-			spin_lock_irqsave(&s->lock, flags);
-			if (val == AFMT_S16_LE)
-				s->sctrl |= SCTRL_P1SEB;
-			else
-				s->sctrl &= ~SCTRL_P1SEB;
-			outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		return put_user((s->sctrl & SCTRL_P1SEB) ? AFMT_S16_LE : AFMT_U8, p);
-
-        case SNDCTL_DSP_POST:
-                return 0;
-
-        case SNDCTL_DSP_GETTRIGGER:
-		return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, p);
-						
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val & PCM_ENABLE_OUTPUT) {
-			if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
-				return ret;
-			s->dma_dac1.enabled = 1;
-			start_dac1(s);
-		} else {
-			s->dma_dac1.enabled = 0;
-			stop_dac1(s);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-		abinfo.fragsize = s->dma_dac1.fragsize;
-		count = s->dma_dac1.count;
-		if (count < 0)
-			count = 0;
-                abinfo.bytes = s->dma_dac1.dmasize - count;
-                abinfo.fragstotal = s->dma_dac1.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_GETODELAY:
-		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-                count = s->dma_dac1.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		return put_user(count, p);
-
-        case SNDCTL_DSP_GETOPTR:
-		if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_update_ptr(s);
-                cinfo.bytes = s->dma_dac1.total_bytes;
-		count = s->dma_dac1.count;
-		if (count < 0)
-			count = 0;
-                cinfo.blocks = count >> s->dma_dac1.fragshift;
-                cinfo.ptr = s->dma_dac1.hwptr;
-		if (s->dma_dac1.mapped)
-			s->dma_dac1.count &= s->dma_dac1.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETBLKSIZE:
-		if ((val = prog_dmabuf_dac1(s)))
-			return val;
-                return put_user(s->dma_dac1.fragsize, p);
-
-        case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, p))
-			return -EFAULT;
-		s->dma_dac1.ossfragshift = val & 0xffff;
-		s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
-		if (s->dma_dac1.ossfragshift < 4)
-			s->dma_dac1.ossfragshift = 4;
-		if (s->dma_dac1.ossfragshift > 15)
-			s->dma_dac1.ossfragshift = 15;
-		if (s->dma_dac1.ossmaxfrags < 4)
-			s->dma_dac1.ossmaxfrags = 4;
-		return 0;
-
-        case SNDCTL_DSP_SUBDIVIDE:
-		if (s->dma_dac1.subdivision)
-			return -EINVAL;
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		s->dma_dac1.subdivision = val;
-		return 0;
-
-        case SOUND_PCM_READ_RATE:
-		return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p);
-
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
-
-        case SOUND_PCM_READ_BITS:
-		return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, p);
-
-        case SOUND_PCM_WRITE_FILTER:
-        case SNDCTL_DSP_SETSYNCRO:
-        case SOUND_PCM_READ_FILTER:
-                return -EINVAL;
-		
-	}
-	return mixer_ioctl(s, cmd, arg);
-}
-
-static int es1370_open_dac(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	struct list_head *list;
-	struct es1370_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct es1370_state, devs);
-		if (!((s->dev_dac ^ minor) & ~0xf))
-			break;
-	}
-       	VALIDATE_STATE(s);
-       	/* we allow opening with O_RDWR, most programs do it although they will only write */
-#if 0
-	if (file->f_mode & FMODE_READ)
-		return -EPERM;
-#endif
-	if (!(file->f_mode & FMODE_WRITE))
-		return -EINVAL;
-       	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & FMODE_DAC) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
-	s->dma_dac1.enabled = 1;
-	spin_lock_irqsave(&s->lock, flags);
-	s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL);
-      	s->sctrl &= ~SCTRL_P1FMT;
-	if ((minor & 0xf) == SND_DEV_DSP16)
-		s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P1FMT;
-	else
-		s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P1FMT;
-	outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->open_mode |= FMODE_DAC;
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int es1370_release_dac(struct inode *inode, struct file *file)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	drain_dac1(s, file->f_flags & O_NONBLOCK);
-	mutex_lock(&s->open_mutex);
-	stop_dac1(s);
-	dealloc_dmabuf(s, &s->dma_dac1);
-	s->open_mode &= ~FMODE_DAC;
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations es1370_dac_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.write		= es1370_write_dac,
-	.poll		= es1370_poll_dac,
-	.ioctl		= es1370_ioctl_dac,
-	.mmap		= es1370_mmap_dac,
-	.open		= es1370_open_dac,
-	.release	= es1370_release_dac,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	if (count == 0)
-		return 0;
-	ret = 0;
-        add_wait_queue(&s->midi.iwait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.ird;
-		cnt = MIDIINBUF - ptr;
-		if (s->midi.icnt < cnt)
-			cnt = s->midi.icnt;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		ptr = (ptr + cnt) % MIDIINBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.ird = ptr;
-		s->midi.icnt -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		break;
-	}
-	__set_current_state(TASK_RUNNING);
-        remove_wait_queue(&s->midi.iwait, &wait);
-	return ret;
-}
-
-static ssize_t es1370_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	if (count == 0)
-		return 0;
-	ret = 0;
-        add_wait_queue(&s->midi.owait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.owr;
-		cnt = MIDIOUTBUF - ptr;
-		if (s->midi.ocnt + cnt > MIDIOUTBUF)
-			cnt = MIDIOUTBUF - s->midi.ocnt;
-		if (cnt <= 0) {
-			__set_current_state(TASK_INTERRUPTIBLE);
-			es1370_handle_midi(s);
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		ptr = (ptr + cnt) % MIDIOUTBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.owr = ptr;
-		s->midi.ocnt += cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		spin_lock_irqsave(&s->lock, flags);
-		es1370_handle_midi(s);
-		spin_unlock_irqrestore(&s->lock, flags);
-	}
-	__set_current_state(TASK_RUNNING);
-        remove_wait_queue(&s->midi.owait, &wait);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1370_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE)
-		poll_wait(file, &s->midi.owait, wait);
-	if (file->f_mode & FMODE_READ)
-		poll_wait(file, &s->midi.iwait, wait);
-	spin_lock_irqsave(&s->lock, flags);
-	if (file->f_mode & FMODE_READ) {
-		if (s->midi.icnt > 0)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->midi.ocnt < MIDIOUTBUF)
-			mask |= POLLOUT | POLLWRNORM;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int es1370_midi_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	struct list_head *list;
-	struct es1370_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct es1370_state, devs);
-		if (s->dev_midi == minor)
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-		outb(UCTRL_CNTRL_SWR, s->io+ES1370_REG_UART_CONTROL);
-		outb(0, s->io+ES1370_REG_UART_CONTROL);
-		outb(0, s->io+ES1370_REG_UART_TEST);
-	}
-	if (file->f_mode & FMODE_READ) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-	}
-	s->ctrl |= CTRL_UART_EN;
-	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	es1370_handle_midi(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int es1370_midi_release(struct inode *inode, struct file *file)
-{
-	struct es1370_state *s = (struct es1370_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	unsigned count, tmo;
-
-	VALIDATE_STATE(s);
-
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE) {
-		add_wait_queue(&s->midi.owait, &wait);
-		for (;;) {
-			__set_current_state(TASK_INTERRUPTIBLE);
-			spin_lock_irqsave(&s->lock, flags);
-			count = s->midi.ocnt;
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (count <= 0)
-				break;
-			if (signal_pending(current))
-				break;
-			if (file->f_flags & O_NONBLOCK) 
-				break;
-			tmo = (count * HZ) / 3100;
-			if (!schedule_timeout(tmo ? : 1) && tmo)
-				DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");)
-		}
-		remove_wait_queue(&s->midi.owait, &wait);
-		set_current_state(TASK_RUNNING);
-	}
-	mutex_lock(&s->open_mutex);
-	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		s->ctrl &= ~CTRL_UART_EN;
-		outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations es1370_midi_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= es1370_midi_read,
-	.write		= es1370_midi_write,
-	.poll		= es1370_midi_poll,
-	.open		= es1370_midi_open,
-	.release	= es1370_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int lineout[NR_DEVICE];
-static int micbias[NR_DEVICE];
-
-static unsigned int devindex;
-
-module_param_array(lineout, bool, NULL, 0);
-MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
-module_param_array(micbias, bool, NULL, 0);
-MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("ES1370 AudioPCI Driver");
-MODULE_LICENSE("GPL");
-
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
-	int mixch;
-	int vol;
-} initvol[] __devinitdata = {
-	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
-	{ SOUND_MIXER_WRITE_PCM, 0x4040 },
-	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
-	{ SOUND_MIXER_WRITE_CD, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE1, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE2, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE3, 0x4040 },
-	{ SOUND_MIXER_WRITE_MIC, 0x4040 },
-	{ SOUND_MIXER_WRITE_OGAIN, 0x4040 }
-};
-
-#ifdef SUPPORT_JOYSTICK
-
-static int __devinit es1370_register_gameport(struct es1370_state *s)
-{
-	struct gameport *gp;
-
-	if (!request_region(0x200, JOY_EXTENT, "es1370")) {
-		printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
-		return -EBUSY;
-	}
-
-	s->gameport = gp = gameport_allocate_port();
-	if (!gp) {
-		printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
-		release_region(0x200, JOY_EXTENT);
-		return -ENOMEM;
-	}
-
-	gameport_set_name(gp, "ESS1370");
-	gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
-	gp->dev.parent = &s->dev->dev;
-	gp->io = 0x200;
-
-	s->ctrl |= CTRL_JYSTK_EN;
-	outl(s->ctrl, s->io + ES1370_REG_CONTROL);
-
-	gameport_register_port(gp);
-
-	return 0;
-}
-
-static inline void es1370_unregister_gameport(struct es1370_state *s)
-{
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-		gameport_unregister_port(s->gameport);
-		release_region(gpio, JOY_EXTENT);
-
-	}
-}
-
-#else
-static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; }
-static inline void es1370_unregister_gameport(struct es1370_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
-	struct es1370_state *s;
-	mm_segment_t fs;
-	int i, val, ret;
-
-	if ((ret=pci_enable_device(pcidev)))
-		return ret;
-
-	if ( !(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
-	     !pci_resource_start(pcidev, 0)
-	)
-		return -ENODEV;
-	if (pcidev->irq == 0) 
-		return -ENODEV;
-	i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
-	if (i) {
-		printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
-		return i;
-	}
-	if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) {
-		printk(KERN_WARNING "es1370: out of memory\n");
-		return -ENOMEM;
-	}
-	memset(s, 0, sizeof(struct es1370_state));
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac1.wait);
-	init_waitqueue_head(&s->dma_dac2.wait);
-	init_waitqueue_head(&s->open_wait);
-	init_waitqueue_head(&s->midi.iwait);
-	init_waitqueue_head(&s->midi.owait);
-	mutex_init(&s->open_mutex);
-	spin_lock_init(&s->lock);
-	s->magic = ES1370_MAGIC;
-	s->dev = pcidev;
-	s->io = pci_resource_start(pcidev, 0);
-	s->irq = pcidev->irq;
-	if (!request_region(s->io, ES1370_EXTENT, "es1370")) {
-		printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
-		ret = -EBUSY;
-		goto err_region;
-	}
-	if ((ret=request_irq(s->irq, es1370_interrupt, IRQF_SHARED, "es1370",s))) {
-		printk(KERN_ERR "es1370: irq %u in use\n", s->irq);
-		goto err_irq;
-	}
-
-	/* initialize codec registers */
-	/* note: setting CTRL_SERR_DIS is reported to break
-	 * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
-	s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
-	if (lineout[devindex])
-		s->ctrl |= CTRL_XCTL0;
-	if (micbias[devindex])
-		s->ctrl |= CTRL_XCTL1;
-	s->sctrl = 0;
-	printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n",
-	       s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in",
-	       (s->ctrl & CTRL_XCTL1) ? "1" : "0");
-	/* register devices */
-	if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) {
-		ret = s->dev_audio;
-		goto err_dev1;
-	}
-	if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) {
-		ret = s->dev_mixer;
-		goto err_dev2;
-	}
-	if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) {
-		ret = s->dev_dac;
-		goto err_dev3;
-	}
-	if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) {
-		ret = s->dev_midi;
-		goto err_dev4;
-	}
-	/* initialize the chips */
-	outl(s->ctrl, s->io+ES1370_REG_CONTROL);
-	outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
-	/* point phantom write channel to "bugbuf" */
-	s->bugbuf_cpu = pci_alloc_consistent(pcidev,16,&s->bugbuf_dma);
-	if (!s->bugbuf_cpu) {
-		ret = -ENOMEM;
-		goto err_dev5;
-	}
-	outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
-	outl(s->bugbuf_dma, s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
-	outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
-	pci_set_master(pcidev);  /* enable bus mastering */
-	wrcodec(s, 0x16, 3); /* no RST, PD */
-	wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!!  */
-	wrcodec(s, 0x18, 0); /* recording source is mixer */
-	wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */
-	s->mix.imix = 1;
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD;
-	mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
-	for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
-		val = initvol[i].vol;
-		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
-	}
-	set_fs(fs);
-
-	es1370_register_gameport(s);
-
-	/* store it in the driver field */
-	pci_set_drvdata(pcidev, s);
-	/* put it into driver list */
-	list_add_tail(&s->devs, &devs);
-	/* increment devindex */
-	if (devindex < NR_DEVICE-1)
-		devindex++;
-	return 0;
-
- err_dev5:
-	unregister_sound_midi(s->dev_midi);
- err_dev4:
-	unregister_sound_dsp(s->dev_dac);
- err_dev3:
-	unregister_sound_mixer(s->dev_mixer);
- err_dev2:
-	unregister_sound_dsp(s->dev_audio);
- err_dev1:
-	printk(KERN_ERR "es1370: cannot register misc device\n");
-	free_irq(s->irq, s);
- err_irq:
-	release_region(s->io, ES1370_EXTENT);
- err_region:
-	kfree(s);
-	return ret;
-}
-
-static void __devexit es1370_remove(struct pci_dev *dev)
-{
-	struct es1370_state *s = pci_get_drvdata(dev);
-
-	if (!s)
-		return;
-	list_del(&s->devs);
-	outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */
-	outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
-	synchronize_irq(s->irq);
-	free_irq(s->irq, s);
-	es1370_unregister_gameport(s);
-	release_region(s->io, ES1370_EXTENT);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->dev_mixer);
-	unregister_sound_dsp(s->dev_dac);
-	unregister_sound_midi(s->dev_midi);
-	pci_free_consistent(dev, 16, s->bugbuf_cpu, s->bugbuf_dma);
-	kfree(s);
-	pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
-	{ PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver es1370_driver = {
-	.name		= "es1370",
-	.id_table	= id_table,
-	.probe		= es1370_probe,
-	.remove		= __devexit_p(es1370_remove),
-};
-
-static int __init init_es1370(void)
-{
-	printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n");
-	return pci_register_driver(&es1370_driver);
-}
-
-static void __exit cleanup_es1370(void)
-{
-	printk(KERN_INFO "es1370: unloading\n");
-	pci_unregister_driver(&es1370_driver);
-}
-
-module_init(init_es1370);
-module_exit(cleanup_es1370);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: es1370=lineout[,micbias]] */
-
-static int __init es1370_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= NR_DEVICE)
-		return 0;
-
-	(void)
-	((get_option(&str,&lineout [nr_dev]) == 2)
-	 && get_option(&str,&micbias [nr_dev])
-	);
-
-	nr_dev++;
-	return 1;
-}
-
-__setup("es1370=", es1370_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
deleted file mode 100644
index 82f40a0..0000000
--- a/sound/oss/esssolo1.c
+++ /dev/null
@@ -1,2516 +0,0 @@
-/****************************************************************************/
-
-/*
- *      esssolo1.c  --  ESS Technology Solo1 (ES1946) audio driver.
- *
- *      Copyright (C) 1998-2001, 2003  Thomas Sailer (t.sailer@alumni.ethz.ch)
- *
- *      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.
- *
- * Module command line parameters:
- *   none so far
- *
- *  Supported devices:
- *  /dev/dsp    standard /dev/dsp device, (mostly) OSS compatible
- *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
- *  /dev/midi   simple MIDI UART interface, no ioctl
- *
- *  Revision history
- *    10.11.1998   0.1   Initial release (without any hardware)
- *    22.03.1999   0.2   cinfo.blocks should be reset after GETxPTR ioctl.
- *                       reported by Johan Maes <joma@telindus.be>
- *                       return EAGAIN instead of EBUSY when O_NONBLOCK
- *                       read/write cannot be executed
- *    07.04.1999   0.3   implemented the following ioctl's: SOUND_PCM_READ_RATE, 
- *                       SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
- *                       Alpha fixes reported by Peter Jones <pjones@redhat.com>
- *    15.06.1999   0.4   Fix bad allocation bug.
- *                       Thanks to Deti Fliegl <fliegl@in.tum.de>
- *    28.06.1999   0.5   Add pci_set_master
- *    12.08.1999   0.6   Fix MIDI UART crashing the driver
- *                       Changed mixer semantics from OSS documented
- *                       behaviour to OSS "code behaviour".
- *                       Recording might actually work now.
- *                       The real DDMA controller address register is at PCI config
- *                       0x60, while the register at 0x18 is used as a placeholder
- *                       register for BIOS address allocation. This register
- *                       is supposed to be copied into 0x60, according
- *                       to the Solo1 datasheet. When I do that, I can access
- *                       the DDMA registers except the mask bit, which
- *                       is stuck at 1. When I copy the contents of 0x18 +0x10
- *                       to the DDMA base register, everything seems to work.
- *                       The fun part is that the Windows Solo1 driver doesn't
- *                       seem to do these tricks.
- *                       Bugs remaining: plops and clicks when starting/stopping playback
- *    31.08.1999   0.7   add spin_lock_init
- *                       replaced current->state = x with set_current_state(x)
- *    03.09.1999   0.8   change read semantics for MIDI to match
- *                       OSS more closely; remove possible wakeup race
- *    07.10.1999   0.9   Fix initialization; complain if sequencer writes time out
- *                       Revised resource grabbing for the FM synthesizer
- *    28.10.1999   0.10  More waitqueue races fixed
- *    09.12.1999   0.11  Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
- *                       Disabling recording on Alpha
- *    12.01.2000   0.12  Prevent some ioctl's from returning bad count values on underrun/overrun;
- *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
- *                       Integrated (aka redid 8-)) APM support patch by Zach Brown
- *    07.02.2000   0.13  Use pci_alloc_consistent and pci_register_driver
- *    19.02.2000   0.14  Use pci_dma_supported to determine if recording should be disabled
- *    13.03.2000   0.15  Reintroduce initialization of a couple of PCI config space registers
- *    21.11.2000   0.16  Initialize dma buffers in poll, otherwise poll may return a bogus mask
- *    12.12.2000   0.17  More dma buffer initializations, patch from
- *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- *    31.01.2001   0.18  Register/Unregister gameport, original patch from
- *                       Nathaniel Daw <daw@cs.cmu.edu>
- *                       Fix SETTRIGGER non OSS API conformity
- *    10.03.2001         provide abs function, prevent picking up a bogus kernel macro
- *                       for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
- *    15.05.2001         pci_enable_device moved, return values in probe cleaned
- *                       up. Marcus Meissner <mm@caldera.de>
- *    22.05.2001   0.19  more cleanups, changed PM to PCI 2.4 style, got rid
- *                       of global list of devices, using pci device data.
- *                       Marcus Meissner <mm@caldera.de>
- *    03.01.2003   0.20  open_mode fixes from Georg Acher <acher@in.tum.de>
- */
-
-/*****************************************************************************/
-      
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/gameport.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "dm.h"
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_ESS
-#define PCI_VENDOR_ID_ESS         0x125d
-#endif
-#ifndef PCI_DEVICE_ID_ESS_SOLO1
-#define PCI_DEVICE_ID_ESS_SOLO1   0x1969
-#endif
-
-#define SOLO1_MAGIC  ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
-
-#define DDMABASE_OFFSET           0    /* chip bug workaround kludge */
-#define DDMABASE_EXTENT           16
-
-#define IOBASE_EXTENT             16
-#define SBBASE_EXTENT             16
-#define VCBASE_EXTENT             (DDMABASE_EXTENT+DDMABASE_OFFSET)
-#define MPUBASE_EXTENT            4
-#define GPBASE_EXTENT             4
-#define GAMEPORT_EXTENT		  4
-
-#define FMSYNTH_EXTENT            4
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF  256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define FMODE_DMFM 0x10
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-static struct pci_driver solo1_driver;
-
-/* --------------------------------------------------------------------- */
-
-struct solo1_state {
-	/* magic */
-	unsigned int magic;
-
-	/* the corresponding pci_dev structure */
-	struct pci_dev *dev;
-
-	/* soundcore stuff */
-	int dev_audio;
-	int dev_mixer;
-	int dev_midi;
-	int dev_dmfm;
-
-	/* hardware resources */
-	unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */
-	unsigned int irq;
-
-	/* mixer registers */
-	struct {
-		unsigned short vol[10];
-		unsigned int recsrc;
-		unsigned int modcnt;
-		unsigned short micpreamp;
-	} mix;
-
-	/* wave stuff */
-	unsigned fmt;
-	unsigned channels;
-	unsigned rate;
-	unsigned char clkdiv;
-	unsigned ena;
-
-	spinlock_t lock;
-	struct mutex open_mutex;
-	mode_t open_mode;
-	wait_queue_head_t open_wait;
-
-	struct dmabuf {
-		void *rawbuf;
-		dma_addr_t dmaaddr;
-		unsigned buforder;
-		unsigned numfrag;
-		unsigned fragshift;
-		unsigned hwptr, swptr;
-		unsigned total_bytes;
-		int count;
-		unsigned error; /* over/underrun */
-		wait_queue_head_t wait;
-		/* redundant, but makes calculations easier */
-		unsigned fragsize;
-		unsigned dmasize;
-		unsigned fragsamples;
-		/* OSS stuff */
-		unsigned mapped:1;
-		unsigned ready:1;
-		unsigned endcleared:1;
-		unsigned enabled:1;
-		unsigned ossfragshift;
-		int ossmaxfrags;
-		unsigned subdivision;
-	} dma_dac, dma_adc;
-
-	/* midi stuff */
-	struct {
-		unsigned ird, iwr, icnt;
-		unsigned ord, owr, ocnt;
-		wait_queue_head_t iwait;
-		wait_queue_head_t owait;
-		struct timer_list timer;
-		unsigned char ibuf[MIDIINBUF];
-		unsigned char obuf[MIDIOUTBUF];
-	} midi;
-
-#if SUPPORT_JOYSTICK
-	struct gameport *gameport;
-#endif
-};
-
-/* --------------------------------------------------------------------- */
-
-static inline void write_seq(struct solo1_state *s, unsigned char data)
-{
-        int i;
-	unsigned long flags;
-
-	/* the local_irq_save stunt is to send the data within the command window */
-        for (i = 0; i < 0xffff; i++) {
-		local_irq_save(flags);
-                if (!(inb(s->sbbase+0xc) & 0x80)) {
-                        outb(data, s->sbbase+0xc);
-			local_irq_restore(flags);
-                        return;
-                }
-		local_irq_restore(flags);
-	}
-	printk(KERN_ERR "esssolo1: write_seq timeout\n");
-	outb(data, s->sbbase+0xc);
-}
-
-static inline int read_seq(struct solo1_state *s, unsigned char *data)
-{
-        int i;
-
-        if (!data)
-                return 0;
-        for (i = 0; i < 0xffff; i++)
-                if (inb(s->sbbase+0xe) & 0x80) {
-                        *data = inb(s->sbbase+0xa);
-                        return 1;
-                }
-	printk(KERN_ERR "esssolo1: read_seq timeout\n");
-        return 0;
-}
-
-static inline int reset_ctrl(struct solo1_state *s)
-{
-        int i;
-
-        outb(3, s->sbbase+6); /* clear sequencer and FIFO */
-        udelay(10);
-        outb(0, s->sbbase+6);
-        for (i = 0; i < 0xffff; i++)
-                if (inb(s->sbbase+0xe) & 0x80)
-                        if (inb(s->sbbase+0xa) == 0xaa) {
-				write_seq(s, 0xc6); /* enter enhanced mode */
-                                return 1;
-			}
-        return 0;
-}
-
-static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char data)
-{
-	write_seq(s, reg);
-	write_seq(s, data);
-}
-
-#if 0 /* unused */
-static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
-{
-        unsigned char r;
-
-	write_seq(s, 0xc0);
-	write_seq(s, reg);
-	read_seq(s, &r);
-	return r;
-}
-#endif /* unused */
-
-static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data)
-{
-	outb(reg, s->sbbase+4);
-	outb(data, s->sbbase+5);
-}
-
-static unsigned char read_mixer(struct solo1_state *s, unsigned char reg)
-{
-	outb(reg, s->sbbase+4);
-	return inb(s->sbbase+5);
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_dac(struct solo1_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->ena &= ~FMODE_WRITE;
-	write_mixer(s, 0x78, 0x10);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac(struct solo1_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
-		s->ena |= FMODE_WRITE;
-		write_mixer(s, 0x78, 0x12);
-		udelay(10);
-		write_mixer(s, 0x78, 0x13);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static inline void stop_adc(struct solo1_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->ena &= ~FMODE_READ;
-	write_ctrl(s, 0xb8, 0xe);
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct solo1_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
-	    && s->dma_adc.ready) {
-		s->ena |= FMODE_READ;
-		write_ctrl(s, 0xb8, 0xf);
-#if 0
-		printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf);
-		printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x  stat: 0x%02x\n", 
-		       inb(s->ddmabase+0xf), inw(s->ddmabase+4), inl(s->ddmabase), inb(s->ddmabase+8));
-#endif
-                outb(0, s->ddmabase+0xd); /* master reset */
-		outb(1, s->ddmabase+0xf);  /* mask */
-		outb(0x54/*0x14*/, s->ddmabase+0xb);  /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
-		outl(virt_to_bus(s->dma_adc.rawbuf), s->ddmabase);
-		outw(s->dma_adc.dmasize-1, s->ddmabase+4);
-		outb(0, s->ddmabase+0xf);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-#if 0
-	printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x  SBstat: 0x%02x\n"
-	       KERN_DEBUG "solo1: DMA: stat: 0x%02x  cnt: 0x%04x  mask: 0x%02x\n", 
-	       read_ctrl(s, 0xb8), inb(s->sbbase+0xc), 
-	       inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->ddmabase+0xf));
-	printk(KERN_DEBUG "solo1: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"  
-	       KERN_DEBUG "solo1: B1: 0x%02x  B2: 0x%02x  B4: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n",
-	       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 
-	       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb4), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), 
-	       read_ctrl(s, 0xb9));
-#endif
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db)
-{
-	struct page *page, *pend;
-
-	if (db->rawbuf) {
-		/* undo marking the pages as reserved */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			ClearPageReserved(page);
-		pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
-	}
-	db->rawbuf = NULL;
-	db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db)
-{
-	int order;
-	unsigned bytespersec;
-	unsigned bufs, sample_shift = 0;
-	struct page *page, *pend;
-
-	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-                for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-			if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
-				break;
-		if (!db->rawbuf)
-			return -ENOMEM;
-		db->buforder = order;
-		/* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			SetPageReserved(page);
-	}
-	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
-		sample_shift++;
-	if (s->channels > 1)
-		sample_shift++;
-	bytespersec = s->rate << sample_shift;
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytespersec)
-			db->fragshift = ld2(bytespersec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-	db->fragsamples = db->fragsize >> sample_shift;
-	db->dmasize = db->numfrag << db->fragshift;
-	db->enabled = 1;
-	return 0;
-}
-
-static inline int prog_dmabuf_adc(struct solo1_state *s)
-{
-	unsigned long va;
-	int c;
-
-	stop_adc(s);
-	/* check if PCI implementation supports 24bit busmaster DMA */
-	if (s->dev->dma_mask > 0xffffff)
-		return -EIO;
-	if ((c = prog_dmabuf(s, &s->dma_adc)))
-		return c;
-	va = s->dma_adc.dmaaddr;
-	if ((va & ~((1<<24)-1)))
-		panic("solo1: buffer above 16M boundary");
-	outb(0, s->ddmabase+0xd);  /* clear */
-	outb(1, s->ddmabase+0xf); /* mask */
-	/*outb(0, s->ddmabase+8);*/  /* enable (enable is active low!) */
-	outb(0x54, s->ddmabase+0xb);  /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
-	outl(va, s->ddmabase);
-	outw(s->dma_adc.dmasize-1, s->ddmabase+4);
-	c = - s->dma_adc.fragsamples;
-	write_ctrl(s, 0xa4, c);
-	write_ctrl(s, 0xa5, c >> 8);
-	outb(0, s->ddmabase+0xf);
-	s->dma_adc.ready = 1;
-	return 0;
-}
-
-static int prog_dmabuf_dac(struct solo1_state *s)
-{
-	unsigned long va;
-	int c;
-
-	stop_dac(s);
-	if ((c = prog_dmabuf(s, &s->dma_dac)))
-		return c;
-	memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
-	va = s->dma_dac.dmaaddr;
-	if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))
-		panic("solo1: buffer crosses 1M boundary");
-	outl(va, s->iobase);
-	/* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */
-	outw(s->dma_dac.dmasize, s->iobase+4);
-	c = - s->dma_dac.fragsamples;
-	write_mixer(s, 0x74, c);
-	write_mixer(s, 0x76, c >> 8);
-	outb(0xa, s->iobase+6);
-	s->dma_dac.ready = 1;
-	return 0;
-}
-
-static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
-{
-	if (bptr + len > bsize) {
-		unsigned x = bsize - bptr;
-		memset(((char *)buf) + bptr, c, x);
-		bptr = 0;
-		len -= x;
-	}
-	memset(((char *)buf) + bptr, c, len);
-}
-
-/* call with spinlock held! */
-
-static void solo1_update_ptr(struct solo1_state *s)
-{
-	int diff;
-	unsigned hwptr;
-
-	/* update ADC pointer */
-	if (s->ena & FMODE_READ) {
-		hwptr = (s->dma_adc.dmasize - 1 - inw(s->ddmabase+4)) % s->dma_adc.dmasize;
-                diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
-                s->dma_adc.hwptr = hwptr;
-		s->dma_adc.total_bytes += diff;
-		s->dma_adc.count += diff;
-#if 0
-		printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",
-		       s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);
-#endif
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-				wake_up(&s->dma_adc.wait);
-		} else {
-			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-				s->ena &= ~FMODE_READ;
-				write_ctrl(s, 0xb8, 0xe);
-				s->dma_adc.error++;
-			}
-			if (s->dma_adc.count > 0)
-				wake_up(&s->dma_adc.wait);
-		}
-	}
-	/* update DAC pointer */
-	if (s->ena & FMODE_WRITE) {
-                hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % s->dma_dac.dmasize;
-                diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-                s->dma_dac.hwptr = hwptr;
-		s->dma_dac.total_bytes += diff;
-#if 0
-		printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n",
-		       s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count);
-#endif
-		if (s->dma_dac.mapped) {
-			s->dma_dac.count += diff;
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
-				wake_up(&s->dma_dac.wait);
-		} else {
-			s->dma_dac.count -= diff;
-			if (s->dma_dac.count <= 0) {
-				s->ena &= ~FMODE_WRITE;
-				write_mixer(s, 0x78, 0x12);
-				s->dma_dac.error++;
-			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
-				clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr,
-					      s->dma_dac.fragsize, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80);
-				s->dma_dac.endcleared = 1;
-			}
-			if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
-				wake_up(&s->dma_dac.wait);
-		}
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-static void prog_codec(struct solo1_state *s)
-{
-	unsigned long flags;
-	int fdiv, filter;
-	unsigned char c;
-
-	reset_ctrl(s);
-	write_seq(s, 0xd3);
-	/* program sampling rates */
-	filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */
-	fdiv = 256 - 7160000 / (filter * 82);
-	spin_lock_irqsave(&s->lock, flags);
-	write_ctrl(s, 0xa1, s->clkdiv);
-	write_ctrl(s, 0xa2, fdiv);
-	write_mixer(s, 0x70, s->clkdiv);
-	write_mixer(s, 0x72, fdiv);
-	/* program ADC parameters */
-	write_ctrl(s, 0xb8, 0xe);
-	write_ctrl(s, 0xb9, /*0x1*/0);
-	write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12);
-	c = 0xd0;
-	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
-		c |= 0x04;
-	if (s->fmt & (AFMT_S16_LE | AFMT_S8))
-		c |= 0x20;
-	if (s->channels > 1)
-		c ^= 0x48;
-	write_ctrl(s, 0xb7, (c & 0x70) | 1);
-	write_ctrl(s, 0xb7, c);
-	write_ctrl(s, 0xb1, 0x50);
-	write_ctrl(s, 0xb2, 0x50);
-	/* program DAC parameters */
-	c = 0x40;
-	if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
-		c |= 1;
-	if (s->fmt & (AFMT_S16_LE | AFMT_S8))
-		c |= 4;
-	if (s->channels > 1)
-		c |= 2;
-	write_mixer(s, 0x7a, c);
-	write_mixer(s, 0x78, 0x10);
-	s->ena = 0;
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n";
-
-#define VALIDATE_STATE(s)                         \
-({                                                \
-	if (!(s) || (s)->magic != SOLO1_MAGIC) { \
-		printk(invalid_magic);            \
-		return -ENXIO;                    \
-	}                                         \
-})
-
-/* --------------------------------------------------------------------- */
-
-static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg)
-{
-	static const unsigned int mixer_src[8] = {
-		SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,
-		SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0
-	};
-	static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
-		[SOUND_MIXER_PCM]     = 1,   /* voice */
-		[SOUND_MIXER_SYNTH]   = 2,   /* FM */
-		[SOUND_MIXER_CD]      = 3,   /* CD */
-		[SOUND_MIXER_LINE]    = 4,   /* Line */
-		[SOUND_MIXER_LINE1]   = 5,   /* AUX */
-		[SOUND_MIXER_MIC]     = 6,   /* Mic */
-		[SOUND_MIXER_LINE2]   = 7,   /* Mono in */
-		[SOUND_MIXER_SPEAKER] = 8,   /* Speaker */
-		[SOUND_MIXER_RECLEV]  = 9,   /* Recording level */
-		[SOUND_MIXER_VOLUME]  = 10   /* Master Volume */
-	};
-	static const unsigned char mixreg[] = {
-		0x7c,   /* voice */
-		0x36,   /* FM */
-		0x38,   /* CD */
-		0x3e,   /* Line */
-		0x3a,   /* AUX */
-		0x1a,   /* Mic */
-		0x6d    /* Mono in */
-	};
-	unsigned char l, r, rl, rr, vidx;
-	int i, val;
-	int __user *p = (int __user *)arg;
-
-	VALIDATE_STATE(s);
-
-	if (cmd == SOUND_MIXER_PRIVATE1) {
-		/* enable/disable/query mixer preamp */
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != -1) {
-			val = val ? 0xff : 0xf7;
-			write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
-		}
-		val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
-		return put_user(val, p);
-	}
-	if (cmd == SOUND_MIXER_PRIVATE2) {
-		/* enable/disable/query spatializer */
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != -1) {
-			val &= 0x3f;
-			write_mixer(s, 0x52, val);
-			write_mixer(s, 0x50, val ? 0x08 : 0);
-		}
-		return put_user(read_mixer(s, 0x52), p);
-	}
-        if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		strncpy(info.id, "Solo1", sizeof(info.id));
-		strncpy(info.name, "ESS Solo1", sizeof(info.name));
-		info.modify_counter = s->mix.modcnt;
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		strncpy(info.id, "Solo1", sizeof(info.id));
-		strncpy(info.name, "ESS Solo1", sizeof(info.name));
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, p);
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
-        if (_SIOC_DIR(cmd) == _SIOC_READ) {
-                switch (_IOC_NR(cmd)) {
-                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			return put_user(mixer_src[read_mixer(s, 0x1c) & 7], p);
-
-                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
-					SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
-					SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV |
-					SOUND_MASK_SPEAKER, p);
-
-                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, p);
-
-                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
-					SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
-					SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, p);
-			
-                case SOUND_MIXER_CAPS:
-			return put_user(SOUND_CAP_EXCL_INPUT, p);
-
-		default:
-			i = _IOC_NR(cmd);
-                        if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
-                                return -EINVAL;
-			return put_user(s->mix.vol[vidx-1], p);
-		}
-	}
-        if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) 
-		return -EINVAL;
-	s->mix.modcnt++;
-	switch (_IOC_NR(cmd)) {
-	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-#if 0
-	        {
-			static const unsigned char regs[] = {
-				0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
-			};
-			int i;
-			
-			for (i = 0; i < sizeof(regs); i++)
-				printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
-				       regs[i], read_mixer(s, regs[i]));
-			printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
-			       0xb4, read_ctrl(s, 0xb4));
-		}
-#endif
-	        if (get_user(val, p))
-			return -EFAULT;
-                i = hweight32(val);
-                if (i == 0)
-                        return 0;
-                else if (i > 1) 
-                        val &= ~mixer_src[read_mixer(s, 0x1c) & 7];
-		for (i = 0; i < 8; i++) {
-			if (mixer_src[i] & val)
-				break;
-		}
-		if (i > 7)
-			return 0;
-		write_mixer(s, 0x1c, i);
-		return 0;
-
-	case SOUND_MIXER_VOLUME:
-		if (get_user(val, p))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		r = (val >> 8) & 0xff;
-		if (r > 100)
-			r = 100;
-		if (l < 6) {
-			rl = 0x40;
-			l = 0;
-		} else {
-			rl = (l * 2 - 11) / 3;
-			l = (rl * 3 + 11) / 2;
-		}
-		if (r < 6) {
-			rr = 0x40;
-			r = 0;
-		} else {
-			rr = (r * 2 - 11) / 3;
-			r = (rr * 3 + 11) / 2;
-		}
-		write_mixer(s, 0x60, rl);
-		write_mixer(s, 0x62, rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-                s->mix.vol[9] = ((unsigned int)r << 8) | l;
-#else
-                s->mix.vol[9] = val;
-#endif
-		return put_user(s->mix.vol[9], p);
-
-	case SOUND_MIXER_SPEAKER:
-		if (get_user(val, p))
-			return -EFAULT;
-		l = val & 0xff;
-		if (l > 100)
-			l = 100;
-		else if (l < 2)
-			l = 2;
-		rl = (l - 2) / 14;
-		l = rl * 14 + 2;
-		write_mixer(s, 0x3c, rl);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-                s->mix.vol[7] = l * 0x101;
-#else
-                s->mix.vol[7] = val;
-#endif
-		return put_user(s->mix.vol[7], p);
-
-	case SOUND_MIXER_RECLEV:
-		if (get_user(val, p))
-			return -EFAULT;
-		l = (val << 1) & 0x1fe;
-		if (l > 200)
-			l = 200;
-		else if (l < 5)
-			l = 5;
-		r = (val >> 7) & 0x1fe;
-		if (r > 200)
-			r = 200;
-		else if (r < 5)
-			r = 5;
-		rl = (l - 5) / 13;
-		rr = (r - 5) / 13;
-		r = (rl * 13 + 5) / 2;
-		l = (rr * 13 + 5) / 2;
-		write_ctrl(s, 0xb4, (rl << 4) | rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-                s->mix.vol[8] = ((unsigned int)r << 8) | l;
-#else
-                s->mix.vol[8] = val;
-#endif
-		return put_user(s->mix.vol[8], p);
-
-	default:
-		i = _IOC_NR(cmd);
-		if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
-			return -EINVAL;
-		if (get_user(val, p))
-			return -EFAULT;
-		l = (val << 1) & 0x1fe;
-		if (l > 200)
-			l = 200;
-		else if (l < 5)
-			l = 5;
-		r = (val >> 7) & 0x1fe;
-		if (r > 200)
-			r = 200;
-		else if (r < 5)
-			r = 5;
-		rl = (l - 5) / 13;
-		rr = (r - 5) / 13;
-		r = (rl * 13 + 5) / 2;
-		l = (rr * 13 + 5) / 2;
-		write_mixer(s, mixreg[vidx-1], (rl << 4) | rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-                s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;
-#else
-                s->mix.vol[vidx-1] = val;
-#endif
-		return put_user(s->mix.vol[vidx-1], p);
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-static int solo1_open_mixdev(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct solo1_state *s = NULL;
-	struct pci_dev *pci_dev = NULL;
-
-	while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
-		struct pci_driver *drvr;
-		drvr = pci_dev_driver (pci_dev);
-		if (drvr != &solo1_driver)
-			continue;
-		s = (struct solo1_state*)pci_get_drvdata(pci_dev);
-		if (!s)
-			continue;
-		if (s->dev_mixer == minor)
-			break;
-	}
-	if (!s)
-		return -ENODEV;
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	return nonseekable_open(inode, file);
-}
-
-static int solo1_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	return 0;
-}
-
-static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations solo1_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= solo1_ioctl_mixdev,
-	.open		= solo1_open_mixdev,
-	.release	= solo1_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct solo1_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count;
-	unsigned tmo;
-	
-	if (s->dma_dac.mapped)
-		return 0;
-        add_wait_queue(&s->dma_dac.wait, &wait);
-        for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
-                spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-                spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-                        break;
-                if (nonblock) {
-                        remove_wait_queue(&s->dma_dac.wait, &wait);
-                        set_current_state(TASK_RUNNING);
-                        return -EBUSY;
-                }
-		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
-		if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
-			tmo >>= 1;
-		if (s->channels > 1)
-			tmo >>= 1;
-                if (!schedule_timeout(tmo + 1))
-                        printk(KERN_DEBUG "solo1: dma timed out??\n");
-        }
-        remove_wait_queue(&s->dma_dac.wait, &wait);
-        set_current_state(TASK_RUNNING);
-        if (signal_pending(current))
-                return -ERESTARTSYS;
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t solo1_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_adc.mapped)
-		return -ENXIO;
-	if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-	add_wait_queue(&s->dma_adc.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		swptr = s->dma_adc.swptr;
-		cnt = s->dma_adc.dmasize-swptr;
-		if (s->dma_adc.count < cnt)
-			cnt = s->dma_adc.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-#ifdef DEBUGREC
-		printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x  cnt: %u\n", 
-		       read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);
-#endif
-		if (cnt <= 0) {
-			if (s->dma_adc.enabled)
-				start_adc(s);
-#ifdef DEBUGREC
-			printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"
-			       KERN_DEBUG "solo1_read: regs: B1: 0x%02x  B2: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n"
-			       KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"  
-			       KERN_DEBUG "solo1_read: SBstat: 0x%02x  cnt: %u\n",
-			       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 
-			       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), 
-			       inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
-#endif
-			if (inb(s->ddmabase+15) & 1)
-				printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-#ifdef DEBUGREC
-			printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x  A2: 0x%02x  A4: 0x%02x  A5: 0x%02x  A8: 0x%02x\n"
-			       KERN_DEBUG "solo1_read: regs: B1: 0x%02x  B2: 0x%02x  B7: 0x%02x  B8: 0x%02x  B9: 0x%02x\n"
-			       KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"  
-			       KERN_DEBUG "solo1_read: SBstat: 0x%02x  cnt: %u\n",
-			       read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8), 
-			       read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9), 
-			       inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
-#endif
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		swptr = (swptr + cnt) % s->dma_adc.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_adc.swptr = swptr;
-		s->dma_adc.count -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_adc.enabled)
-			start_adc(s);
-#ifdef DEBUGREC
-		printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x  DMAstat: 0x%02x  DMAcnt: 0x%04x  SBstat: 0x%02x\n", 
-		       read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));
-#endif
-	}
-	remove_wait_queue(&s->dma_adc.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static ssize_t solo1_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_dac.mapped)
-		return -ENXIO;
-	if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-#if 0
-	printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x  71: 0x%02x  72: 0x%02x  74: 0x%02x  76: 0x%02x  78: 0x%02x  7A: 0x%02x\n"
-	       KERN_DEBUG "solo1_write: DMA: addr: 0x%08x  cnt: 0x%04x  stat: 0x%02x  SBstat: 0x%02x\n", 
-	       read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76),
-	       read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
-	printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x  reg 7A: 0x%02x  DMAcnt: 0x%04x  DMAstat: 0x%02x  SBstat: 0x%02x\n", 
-	       read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
-#endif
-	ret = 0;
-	add_wait_queue(&s->dma_dac.wait, &wait);	
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		if (s->dma_dac.count < 0) {
-			s->dma_dac.count = 0;
-			s->dma_dac.swptr = s->dma_dac.hwptr;
-		}
-		swptr = s->dma_dac.swptr;
-		cnt = s->dma_dac.dmasize-swptr;
-		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-			cnt = s->dma_dac.dmasize - s->dma_dac.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (s->dma_dac.enabled)
-				start_dac(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_dac.swptr = swptr;
-		s->dma_dac.count += cnt;
-		s->dma_dac.endcleared = 0;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_dac.enabled)
-			start_dac(s);
-	}
-	remove_wait_queue(&s->dma_dac.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready && prog_dmabuf_dac(s))
-			return 0;
-		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready && prog_dmabuf_adc(s))
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	solo1_update_ptr(s);
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-				mask |= POLLIN | POLLRDNORM;
-		} else {
-			if (s->dma_adc.count > 0)
-				mask |= POLLIN | POLLRDNORM;
-		}
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-
-static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	struct dmabuf *db;
-	int ret = -EINVAL;
-	unsigned long size;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf_dac(s)) != 0)
-			goto out;
-		db = &s->dma_dac;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf_adc(s)) != 0)
-			goto out;
-		db = &s->dma_adc;
-	} else 
-		goto out;
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder))
-		goto out;
-	ret = -EAGAIN;
-	if (remap_pfn_range(vma, vma->vm_start,
-				virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
-				size, vma->vm_page_prot))
-		goto out;
-	db->mapped = 1;
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
-	int val, mapped, ret, count;
-        int div1, div2;
-        unsigned rate1, rate2;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	VALIDATE_STATE(s);
-        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
-		return 0;
-		
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-		
-        case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq(s->irq);
-			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq(s->irq);
-			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
-		}
-		prog_codec(s);
-		return 0;
-
-        case SNDCTL_DSP_SPEED:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-			stop_adc(s);
-			stop_dac(s);
-			s->dma_adc.ready = s->dma_dac.ready = 0;
-			/* program sampling rates */
-			if (val > 48000)
-				val = 48000;
-			if (val < 6300)
-				val = 6300;
-			div1 = (768000 + val / 2) / val;
-			rate1 = (768000 + div1 / 2) / div1;
-			div1 = -div1;
-			div2 = (793800 + val / 2) / val;
-			rate2 = (793800 + div2 / 2) / div2;
-			div2 = (-div2) & 0x7f;
-			if (abs(val - rate2) < abs(val - rate1)) {
-				rate1 = rate2;
-				div1 = div2;
-			}
-			s->rate = rate1;
-			s->clkdiv = div1;
-			prog_codec(s);
-		}
-		return put_user(s->rate, p);
-		
-        case SNDCTL_DSP_STEREO:
-                if (get_user(val, p))
-			return -EFAULT;
-		stop_adc(s);
-		stop_dac(s);
-		s->dma_adc.ready = s->dma_dac.ready = 0;
-		/* program channels */
-		s->channels = val ? 2 : 1;
-		prog_codec(s);
-		return 0;
-
-        case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 0) {
-			stop_adc(s);
-			stop_dac(s);
-			s->dma_adc.ready = s->dma_dac.ready = 0;
-			/* program channels */
-			s->channels = (val >= 2) ? 2 : 1;
-			prog_codec(s);
-		}
-		return put_user(s->channels, p);
-
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, p);
-
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			stop_adc(s);
-			stop_dac(s);
-			s->dma_adc.ready = s->dma_dac.ready = 0;
-			/* program format */
-			if (val != AFMT_S16_LE && val != AFMT_U16_LE && 
-			    val != AFMT_S8 && val != AFMT_U8)
-				val = AFMT_U8;
-			s->fmt = val;
-			prog_codec(s);
-		}
-		return put_user(s->fmt, p);
-
-	case SNDCTL_DSP_POST:
-                return 0;
-
-        case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if (file->f_mode & s->ena & FMODE_READ)
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & s->ena & FMODE_WRITE)
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, p);
-
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-					return ret;
-				s->dma_dac.enabled = 1;
-				start_adc(s);
-				if (inb(s->ddmabase+15) & 1)
-					printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
-			} else {
-				s->dma_dac.enabled = 0;
-				stop_adc(s);
-			}
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
-					return ret;
-				s->dma_dac.enabled = 1;
-				start_dac(s);
-			} else {
-				s->dma_dac.enabled = 0;
-				stop_dac(s);
-			}
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		solo1_update_ptr(s);
-		abinfo.fragsize = s->dma_dac.fragsize;
-		count = s->dma_dac.count;
-		if (count < 0)
-			count = 0;
-                abinfo.bytes = s->dma_dac.dmasize - count;
-                abinfo.fragstotal = s->dma_dac.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		solo1_update_ptr(s);
-		abinfo.fragsize = s->dma_adc.fragsize;
-                abinfo.bytes = s->dma_adc.count;
-                abinfo.fragstotal = s->dma_adc.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		solo1_update_ptr(s);
-                count = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		return put_user(count, p);
-
-        case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		solo1_update_ptr(s);
-                cinfo.bytes = s->dma_adc.total_bytes;
-                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
-                cinfo.ptr = s->dma_adc.hwptr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= s->dma_adc.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		solo1_update_ptr(s);
-                cinfo.bytes = s->dma_dac.total_bytes;
-		count = s->dma_dac.count;
-		if (count < 0)
-			count = 0;
-                cinfo.blocks = count >> s->dma_dac.fragshift;
-                cinfo.ptr = s->dma_dac.hwptr;
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= s->dma_dac.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-#if 0
-		printk(KERN_DEBUG "esssolo1: GETOPTR: bytes %u blocks %u ptr %u, buforder %u numfrag %u fragshift %u\n"
-		       KERN_DEBUG "esssolo1: swptr %u count %u fragsize %u dmasize %u fragsamples %u\n",
-		       cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift,
-		       s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples);
-#endif
-		if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf_dac(s)))
-				return val;
-			return put_user(s->dma_dac.fragsize, p);
-		}
-		if ((val = prog_dmabuf_adc(s)))
-			return val;
-		return put_user(s->dma_adc.fragsize, p);
-
-        case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-			return -EINVAL;
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			s->dma_dac.subdivision = val;
-		return 0;
-
-        case SOUND_PCM_READ_RATE:
-		return put_user(s->rate, p);
-
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user(s->channels, p);
-
-        case SOUND_PCM_READ_BITS:
-		return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, p);
-
-        case SOUND_PCM_WRITE_FILTER:
-        case SNDCTL_DSP_SETSYNCRO:
-        case SOUND_PCM_READ_FILTER:
-                return -EINVAL;
-		
-	}
-	return mixer_ioctl(s, cmd, arg);
-}
-
-static int solo1_release(struct inode *inode, struct file *file)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE)
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac(s);
-		outb(0, s->iobase+6);  /* disable DMA */
-		dealloc_dmabuf(s, &s->dma_dac);
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-		outb(1, s->ddmabase+0xf); /* mask DMA channel */
-		outb(0, s->ddmabase+0xd); /* DMA master clear */
-		dealloc_dmabuf(s, &s->dma_adc);
-	}
-	s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static int solo1_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct solo1_state *s = NULL;
-	struct pci_dev *pci_dev = NULL;
-	
-	while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
-		struct pci_driver *drvr;
-
-		drvr = pci_dev_driver(pci_dev);
-		if (drvr != &solo1_driver)
-			continue;
-		s = (struct solo1_state*)pci_get_drvdata(pci_dev);
-		if (!s)
-			continue;
-		if (!((s->dev_audio ^ minor) & ~0xf))
-			break;
-	}
-	if (!s)
-		return -ENODEV;
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	s->fmt = AFMT_U8;
-	s->channels = 1;
-	s->rate = 8000;
-	s->clkdiv = 96 | 0x80;
-	s->ena = 0;
-	s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
-	s->dma_adc.enabled = 1;
-	s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
-	s->dma_dac.enabled = 1;
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_unlock(&s->open_mutex);
-	prog_codec(s);
-	return nonseekable_open(inode, file);
-}
-
-static /*const*/ struct file_operations solo1_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= solo1_read,
-	.write		= solo1_write,
-	.poll		= solo1_poll,
-	.ioctl		= solo1_ioctl,
-	.mmap		= solo1_mmap,
-	.open		= solo1_open,
-	.release	= solo1_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* hold spinlock for the following! */
-static void solo1_handle_midi(struct solo1_state *s)
-{
-	unsigned char ch;
-	int wake;
-
-	if (!(s->mpubase))
-		return;
-	wake = 0;
-	while (!(inb(s->mpubase+1) & 0x80)) {
-		ch = inb(s->mpubase);
-		if (s->midi.icnt < MIDIINBUF) {
-			s->midi.ibuf[s->midi.iwr] = ch;
-			s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
-			s->midi.icnt++;
-		}
-		wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.iwait);
-	wake = 0;
-	while (!(inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
-		outb(s->midi.obuf[s->midi.ord], s->mpubase);
-		s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
-		s->midi.ocnt--;
-		if (s->midi.ocnt < MIDIOUTBUF-16)
-			wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.owait);
-}
-
-static irqreturn_t solo1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct solo1_state *s = (struct solo1_state *)dev_id;
-	unsigned int intsrc;
-	
-	/* fastpath out, to ease interrupt sharing */
-	intsrc = inb(s->iobase+7); /* get interrupt source(s) */
-	if (!intsrc)
-		return IRQ_NONE;
-	(void)inb(s->sbbase+0xe);  /* clear interrupt */
-	spin_lock(&s->lock);
-	/* clear audio interrupts first */
-	if (intsrc & 0x20)
-		write_mixer(s, 0x7a, read_mixer(s, 0x7a) & 0x7f);
-	solo1_update_ptr(s);
-	solo1_handle_midi(s);
-	spin_unlock(&s->lock);
-	return IRQ_HANDLED;
-}
-
-static void solo1_midi_timer(unsigned long data)
-{
-	struct solo1_state *s = (struct solo1_state *)data;
-	unsigned long flags;
-	
-	spin_lock_irqsave(&s->lock, flags);
-	solo1_handle_midi(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->midi.timer.expires = jiffies+1;
-	add_timer(&s->midi.timer);
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t solo1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	if (count == 0)
-		return 0;
-	ret = 0;
-	add_wait_queue(&s->midi.iwait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.ird;
-		cnt = MIDIINBUF - ptr;
-		if (s->midi.icnt < cnt)
-			cnt = s->midi.icnt;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		ptr = (ptr + cnt) % MIDIINBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.ird = ptr;
-		s->midi.icnt -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		break;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&s->midi.iwait, &wait);
-	return ret;
-}
-
-static ssize_t solo1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	if (count == 0)
-		return 0;
-	ret = 0;
-        add_wait_queue(&s->midi.owait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.owr;
-		cnt = MIDIOUTBUF - ptr;
-		if (s->midi.ocnt + cnt > MIDIOUTBUF)
-			cnt = MIDIOUTBUF - s->midi.ocnt;
-		if (cnt <= 0) {
-			__set_current_state(TASK_INTERRUPTIBLE);
-			solo1_handle_midi(s);
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		ptr = (ptr + cnt) % MIDIOUTBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.owr = ptr;
-		s->midi.ocnt += cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		spin_lock_irqsave(&s->lock, flags);
-		solo1_handle_midi(s);
-		spin_unlock_irqrestore(&s->lock, flags);
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&s->midi.owait, &wait);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_flags & FMODE_WRITE)
-		poll_wait(file, &s->midi.owait, wait);
-	if (file->f_flags & FMODE_READ)
-		poll_wait(file, &s->midi.iwait, wait);
-	spin_lock_irqsave(&s->lock, flags);
-	if (file->f_flags & FMODE_READ) {
-		if (s->midi.icnt > 0)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_flags & FMODE_WRITE) {
-		if (s->midi.ocnt < MIDIOUTBUF)
-			mask |= POLLOUT | POLLWRNORM;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int solo1_midi_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	struct solo1_state *s = NULL;
-	struct pci_dev *pci_dev = NULL;
-
-	while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
-		struct pci_driver *drvr;
-
-		drvr = pci_dev_driver(pci_dev);
-		if (drvr != &solo1_driver)
-			continue;
-		s = (struct solo1_state*)pci_get_drvdata(pci_dev);
-		if (!s)
-			continue;
-		if (s->dev_midi == minor)
-			break;
-	}
-	if (!s)
-		return -ENODEV;
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-		outb(0xff, s->mpubase+1); /* reset command */
-		outb(0x3f, s->mpubase+1); /* uart command */
-		if (!(inb(s->mpubase+1) & 0x80))
-			inb(s->mpubase);
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-		outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */
-		init_timer(&s->midi.timer);
-		s->midi.timer.expires = jiffies+1;
-		s->midi.timer.data = (unsigned long)s;
-		s->midi.timer.function = solo1_midi_timer;
-		add_timer(&s->midi.timer);
-	}
-	if (file->f_mode & FMODE_READ) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int solo1_midi_release(struct inode *inode, struct file *file)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	unsigned count, tmo;
-
-	VALIDATE_STATE(s);
-
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE) {
-		add_wait_queue(&s->midi.owait, &wait);
-		for (;;) {
-			__set_current_state(TASK_INTERRUPTIBLE);
-			spin_lock_irqsave(&s->lock, flags);
-			count = s->midi.ocnt;
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (count <= 0)
-				break;
-			if (signal_pending(current))
-				break;
-			if (file->f_flags & O_NONBLOCK)
-				break;
-			tmo = (count * HZ) / 3100;
-			if (!schedule_timeout(tmo ? : 1) && tmo)
-				printk(KERN_DEBUG "solo1: midi timed out??\n");
-		}
-		remove_wait_queue(&s->midi.owait, &wait);
-		set_current_state(TASK_RUNNING);
-	}
-	mutex_lock(&s->open_mutex);
-	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */
-		del_timer(&s->midi.timer);		
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations solo1_midi_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= solo1_midi_read,
-	.write		= solo1_midi_write,
-	.poll		= solo1_midi_poll,
-	.open		= solo1_midi_open,
-	.release	= solo1_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	static const unsigned char op_offset[18] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
-		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15
-	};
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	struct dm_fm_voice v;
-	struct dm_fm_note n;
-	struct dm_fm_params p;
-	unsigned int io;
-	unsigned int regb;
-
-	switch (cmd) {		
-	case FM_IOCTL_RESET:
-		for (regb = 0xb0; regb < 0xb9; regb++) {
-			outb(regb, s->sbbase);
-			outb(0, s->sbbase+1);
-			outb(regb, s->sbbase+2);
-			outb(0, s->sbbase+3);
-		}
-		return 0;
-
-	case FM_IOCTL_PLAY_NOTE:
-		if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
-			return -EFAULT;
-		if (n.voice >= 18)
-			return -EINVAL;
-		if (n.voice >= 9) {
-			regb = n.voice - 9;
-			io = s->sbbase+2;
-		} else {
-			regb = n.voice;
-			io = s->sbbase;
-		}
-		outb(0xa0 + regb, io);
-		outb(n.fnum & 0xff, io+1);
-		outb(0xb0 + regb, io);
-		outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
-		return 0;
-
-	case FM_IOCTL_SET_VOICE:
-		if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
-			return -EFAULT;
-		if (v.voice >= 18)
-			return -EINVAL;
-		regb = op_offset[v.voice];
-		io = s->sbbase + ((v.op & 1) << 1);
-		outb(0x20 + regb, io);
-		outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) | 
-		     ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
-		outb(0x40 + regb, io);
-		outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
-		outb(0x60 + regb, io);
-		outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
-		outb(0x80 + regb, io);
-		outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
-		outb(0xe0 + regb, io);
-		outb(v.waveform & 0x7, io+1);
-		if (n.voice >= 9) {
-			regb = n.voice - 9;
-			io = s->sbbase+2;
-		} else {
-			regb = n.voice;
-			io = s->sbbase;
-		}
-		outb(0xc0 + regb, io);
-		outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
-		     (v.connection & 1), io+1);
-		return 0;
-		
-	case FM_IOCTL_SET_PARAMS:
-		if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
-			return -EFAULT;
-		outb(0x08, s->sbbase);
-		outb((p.kbd_split & 1) << 6, s->sbbase+1);
-		outb(0xbd, s->sbbase);
-		outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
-		     ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1);
-		return 0;
-
-	case FM_IOCTL_SET_OPL:
-		outb(4, s->sbbase+2);
-		outb(arg, s->sbbase+3);
-		return 0;
-
-	case FM_IOCTL_SET_MODE:
-		outb(5, s->sbbase+2);
-		outb(arg & 1, s->sbbase+3);
-		return 0;
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int solo1_dmfm_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct solo1_state *s = NULL;
-	struct pci_dev *pci_dev = NULL;
-
-	while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
-		struct pci_driver *drvr;
-
-		drvr = pci_dev_driver(pci_dev);
-		if (drvr != &solo1_driver)
-			continue;
-		s = (struct solo1_state*)pci_get_drvdata(pci_dev);
-		if (!s)
-			continue;
-		if (s->dev_dmfm == minor)
-			break;
-	}
-	if (!s)
-		return -ENODEV;
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & FMODE_DMFM) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) {
-		mutex_unlock(&s->open_mutex);
-		printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
-		return -EBUSY;
-	}
-	/* init the stuff */
-	outb(1, s->sbbase);
-	outb(0x20, s->sbbase+1); /* enable waveforms */
-	outb(4, s->sbbase+2);
-	outb(0, s->sbbase+3);  /* no 4op enabled */
-	outb(5, s->sbbase+2);
-	outb(1, s->sbbase+3);  /* enable OPL3 */
-	s->open_mode |= FMODE_DMFM;
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int solo1_dmfm_release(struct inode *inode, struct file *file)
-{
-	struct solo1_state *s = (struct solo1_state *)file->private_data;
-	unsigned int regb;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	mutex_lock(&s->open_mutex);
-	s->open_mode &= ~FMODE_DMFM;
-	for (regb = 0xb0; regb < 0xb9; regb++) {
-		outb(regb, s->sbbase);
-		outb(0, s->sbbase+1);
-		outb(regb, s->sbbase+2);
-		outb(0, s->sbbase+3);
-	}
-	release_region(s->sbbase, FMSYNTH_EXTENT);
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations solo1_dmfm_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= solo1_dmfm_ioctl,
-	.open		= solo1_dmfm_open,
-	.release	= solo1_dmfm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
-	int mixch;
-	int vol;
-} initvol[] __devinitdata = {
-	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
-	{ SOUND_MIXER_WRITE_PCM, 0x4040 },
-	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
-	{ SOUND_MIXER_WRITE_CD, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE1, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE2, 0x4040 },
-	{ SOUND_MIXER_WRITE_RECLEV, 0x4040 },
-	{ SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
-	{ SOUND_MIXER_WRITE_MIC, 0x4040 }
-};
-
-static int setup_solo1(struct solo1_state *s)
-{
-	struct pci_dev *pcidev = s->dev;
-	mm_segment_t fs;
-	int i, val;
-
-	/* initialize DDMA base address */
-	printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
-	pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1);
-	/* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
-	pci_write_config_dword(pcidev, 0x50, 0);
-	/* disable legacy audio address decode */
-	pci_write_config_word(pcidev, 0x40, 0x907f);
-
-	/* initialize the chips */
-	if (!reset_ctrl(s)) {
-		printk(KERN_ERR "esssolo1: cannot reset controller\n");
-		return -1;
-	}
-	outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
-	
-	/* initialize mixer regs */
-	write_mixer(s, 0x7f, 0); /* disable music digital recording */
-	write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
-	write_mixer(s, 0x64, 0x45); /* volume control */
-	write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
-	write_mixer(s, 0x50, 0);  /* disable spatializer */
-	write_mixer(s, 0x52, 0);
-	write_mixer(s, 0x14, 0);  /* DAC1 minimum volume */
-	write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
-	outb(0, s->ddmabase+0xd); /* DMA master clear */
-	outb(1, s->ddmabase+0xf); /* mask channel */
-	/*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */
-
-	pci_set_master(pcidev);  /* enable bus mastering */
-	
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	val = SOUND_MASK_LINE;
-	mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
-	for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
-		val = initvol[i].vol;
-		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
-	}
-	val = 1; /* enable mic preamp */
-	mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
-	set_fs(fs);
-	return 0;
-}
-
-static int
-solo1_suspend(struct pci_dev *pci_dev, pm_message_t state) {
-	struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
-	if (!s)
-		return 1;
-	outb(0, s->iobase+6);
-	/* DMA master clear */
-	outb(0, s->ddmabase+0xd); 
-	/* reset sequencer and FIFO */
-	outb(3, s->sbbase+6); 
-	/* turn off DDMA controller address space */
-	pci_write_config_word(s->dev, 0x60, 0); 
-	return 0;
-}
-
-static int
-solo1_resume(struct pci_dev *pci_dev) {
-	struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
-	if (!s)
-		return 1;
-	setup_solo1(s);
-	return 0;
-}
-
-#ifdef SUPPORT_JOYSTICK
-static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
-{
-	struct gameport *gp;
-
-	if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) {
-		printk(KERN_ERR "solo1: gameport io ports are in use\n");
-		return -EBUSY;
-	}
-
-	s->gameport = gp = gameport_allocate_port();
-	if (!gp) {
-		printk(KERN_ERR "solo1: can not allocate memory for gameport\n");
-		release_region(io_port, GAMEPORT_EXTENT);
-		return -ENOMEM;
-	}
-
-	gameport_set_name(gp, "ESS Solo1 Gameport");
-	gameport_set_phys(gp, "isa%04x/gameport0", io_port);
-	gp->dev.parent = &s->dev->dev;
-	gp->io = io_port;
-
-	gameport_register_port(gp);
-
-	return 0;
-}
-
-static inline void solo1_unregister_gameport(struct solo1_state *s)
-{
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-		gameport_unregister_port(s->gameport);
-		release_region(gpio, GAMEPORT_EXTENT);
-	}
-}
-#else
-static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
-static inline void solo1_unregister_gameport(struct solo1_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
-	struct solo1_state *s;
-	int gpio;
-	int ret;
-
- 	if ((ret=pci_enable_device(pcidev)))
-		return ret;
-	if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
-	    !(pci_resource_flags(pcidev, 1) & IORESOURCE_IO) ||
-	    !(pci_resource_flags(pcidev, 2) & IORESOURCE_IO) ||
-	    !(pci_resource_flags(pcidev, 3) & IORESOURCE_IO))
-		return -ENODEV;
-	if (pcidev->irq == 0)
-		return -ENODEV;
-
-	/* Recording requires 24-bit DMA, so attempt to set dma mask
-	 * to 24 bits first, then 32 bits (playback only) if that fails.
-	 */
-	if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK) &&
-	    pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
-		printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
-		return -ENODEV;
-	}
-
-	if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
-		printk(KERN_WARNING "solo1: out of memory\n");
-		return -ENOMEM;
-	}
-	memset(s, 0, sizeof(struct solo1_state));
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac.wait);
-	init_waitqueue_head(&s->open_wait);
-	init_waitqueue_head(&s->midi.iwait);
-	init_waitqueue_head(&s->midi.owait);
-	mutex_init(&s->open_mutex);
-	spin_lock_init(&s->lock);
-	s->magic = SOLO1_MAGIC;
-	s->dev = pcidev;
-	s->iobase = pci_resource_start(pcidev, 0);
-	s->sbbase = pci_resource_start(pcidev, 1);
-	s->vcbase = pci_resource_start(pcidev, 2);
-	s->ddmabase = s->vcbase + DDMABASE_OFFSET;
-	s->mpubase = pci_resource_start(pcidev, 3);
-	gpio = pci_resource_start(pcidev, 4);
-	s->irq = pcidev->irq;
-	ret = -EBUSY;
-	if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
-		printk(KERN_ERR "solo1: io ports in use\n");
-		goto err_region1;
-	}
-	if (!request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1")) {
-		printk(KERN_ERR "solo1: io ports in use\n");
-		goto err_region2;
-	}
-	if (!request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1")) {
-		printk(KERN_ERR "solo1: io ports in use\n");
-		goto err_region3;
-	}
-	if (!request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1")) {
-		printk(KERN_ERR "solo1: io ports in use\n");
-		goto err_region4;
-	}
-	if ((ret=request_irq(s->irq,solo1_interrupt,IRQF_SHARED,"ESS Solo1",s))) {
-		printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
-		goto err_irq;
-	}
-	/* register devices */
-	if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) {
-		ret = s->dev_audio;
-		goto err_dev1;
-	}
-	if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) {
-		ret = s->dev_mixer;
-		goto err_dev2;
-	}
-	if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) {
-		ret = s->dev_midi;
-		goto err_dev3;
-	}
-	if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) {
-		ret = s->dev_dmfm;
-		goto err_dev4;
-	}
-	if (setup_solo1(s)) {
-		ret = -EIO;
-		goto err;
-	}
-	/* register gameport */
-	solo1_register_gameport(s, gpio);
-	/* store it in the driver field */
-	pci_set_drvdata(pcidev, s);
-	return 0;
-
- err:
-	unregister_sound_special(s->dev_dmfm);
- err_dev4:
-	unregister_sound_midi(s->dev_midi);
- err_dev3:
-	unregister_sound_mixer(s->dev_mixer);
- err_dev2:
-	unregister_sound_dsp(s->dev_audio);
- err_dev1:
-	printk(KERN_ERR "solo1: initialisation error\n");
-	free_irq(s->irq, s);
- err_irq:
-	release_region(s->mpubase, MPUBASE_EXTENT);
- err_region4:
-	release_region(s->ddmabase, DDMABASE_EXTENT);
- err_region3:
-	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- err_region2:
-	release_region(s->iobase, IOBASE_EXTENT);
- err_region1:
-	kfree(s);
-	return ret;
-}
-
-static void __devexit solo1_remove(struct pci_dev *dev)
-{
-	struct solo1_state *s = pci_get_drvdata(dev);
-	
-	if (!s)
-		return;
-	/* stop DMA controller */
-	outb(0, s->iobase+6);
-	outb(0, s->ddmabase+0xd); /* DMA master clear */
-	outb(3, s->sbbase+6); /* reset sequencer and FIFO */
-	synchronize_irq(s->irq);
-	pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
-	free_irq(s->irq, s);
-	solo1_unregister_gameport(s);
-	release_region(s->iobase, IOBASE_EXTENT);
-	release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
-	release_region(s->ddmabase, DDMABASE_EXTENT);
-	release_region(s->mpubase, MPUBASE_EXTENT);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->dev_mixer);
-	unregister_sound_midi(s->dev_midi);
-	unregister_sound_special(s->dev_dmfm);
-	kfree(s);
-	pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
-	{ PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-	{ 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver solo1_driver = {
-	.name		= "ESS Solo1",
-	.id_table	= id_table,
-	.probe		= solo1_probe,
-	.remove		= __devexit_p(solo1_remove),
-	.suspend	= solo1_suspend,
-	.resume		= solo1_resume,
-};
-
-
-static int __init init_solo1(void)
-{
-	printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n");
-	return pci_register_driver(&solo1_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("ESS Solo1 Driver");
-MODULE_LICENSE("GPL");
-
-
-static void __exit cleanup_solo1(void)
-{
-	printk(KERN_INFO "solo1: unloading\n");
-	pci_unregister_driver(&solo1_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-module_init(init_solo1);
-module_exit(cleanup_solo1);
-
diff --git a/sound/oss/forte.c b/sound/oss/forte.c
deleted file mode 100644
index ea1c020..0000000
--- a/sound/oss/forte.c
+++ /dev/null
@@ -1,2139 +0,0 @@
-/*
- * forte.c - ForteMedia FM801 OSS Driver
- *
- * Written by Martin K. Petersen <mkp@mkp.net>
- * Copyright (C) 2002 Hewlett-Packard Company
- * Portions Copyright (C) 2003 Martin K. Petersen
- *
- * Latest version: http://mkp.net/forte/
- *
- * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers
- * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik.  Thanks
- * guys!
- *
- * 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.
- *
- * 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/module.h>
-#include <linux/kernel.h>
-
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/pci.h>
-
-#include <linux/delay.h>
-#include <linux/poll.h>
-
-#include <linux/sound.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#define DRIVER_NAME	"forte"
-#define DRIVER_VERSION 	"$Id: forte.c,v 1.63 2003/03/01 05:32:42 mkp Exp $"
-#define PFX 		DRIVER_NAME ": "
-
-#undef M_DEBUG
-
-#ifdef M_DEBUG
-#define DPRINTK(args...) printk(KERN_WARNING args)
-#else
-#define DPRINTK(args...)
-#endif
-
-/* Card capabilities */
-#define FORTE_CAPS              (DSP_CAP_MMAP | DSP_CAP_TRIGGER)
-
-/* Supported audio formats */
-#define FORTE_FMTS		(AFMT_U8 | AFMT_S16_LE)
-
-/* Buffers */
-#define FORTE_MIN_FRAG_SIZE     256
-#define FORTE_MAX_FRAG_SIZE     PAGE_SIZE
-#define FORTE_DEF_FRAG_SIZE     256
-#define FORTE_MIN_FRAGMENTS     2
-#define FORTE_MAX_FRAGMENTS     256
-#define FORTE_DEF_FRAGMENTS     2
-#define FORTE_MIN_BUF_MSECS     500
-#define FORTE_MAX_BUF_MSECS     1000
-
-/* PCI BARs */
-#define FORTE_PCM_VOL           0x00    /* PCM Output Volume */
-#define FORTE_FM_VOL            0x02    /* FM Output Volume */
-#define FORTE_I2S_VOL           0x04    /* I2S Volume */
-#define FORTE_REC_SRC           0x06    /* Record Source */
-#define FORTE_PLY_CTRL          0x08    /* Playback Control */
-#define FORTE_PLY_COUNT         0x0a    /* Playback Count */
-#define FORTE_PLY_BUF1          0x0c    /* Playback Buffer I */
-#define FORTE_PLY_BUF2          0x10    /* Playback Buffer II */
-#define FORTE_CAP_CTRL          0x14    /* Capture Control */
-#define FORTE_CAP_COUNT         0x16    /* Capture Count */
-#define FORTE_CAP_BUF1          0x18    /* Capture Buffer I */
-#define FORTE_CAP_BUF2          0x1c    /* Capture Buffer II */
-#define FORTE_CODEC_CTRL        0x22    /* Codec Control */
-#define FORTE_I2S_MODE          0x24    /* I2S Mode Control */
-#define FORTE_VOLUME            0x26    /* Volume Up/Down/Mute Status */
-#define FORTE_I2C_CTRL          0x29    /* I2C Control */
-#define FORTE_AC97_CMD          0x2a    /* AC'97 Command */
-#define FORTE_AC97_DATA         0x2c    /* AC'97 Data */
-#define FORTE_MPU401_DATA       0x30    /* MPU401 Data */
-#define FORTE_MPU401_CMD        0x31    /* MPU401 Command */
-#define FORTE_GPIO_CTRL         0x52    /* General Purpose I/O Control */
-#define FORTE_GEN_CTRL          0x54    /* General Control */
-#define FORTE_IRQ_MASK          0x56    /* Interrupt Mask */
-#define FORTE_IRQ_STATUS        0x5a    /* Interrupt Status */
-#define FORTE_OPL3_BANK0        0x68    /* OPL3 Status Read / Bank 0 Write */
-#define FORTE_OPL3_DATA0        0x69    /* OPL3 Data 0 Write */
-#define FORTE_OPL3_BANK1        0x6a    /* OPL3 Bank 1 Write */
-#define FORTE_OPL3_DATA1        0x6b    /* OPL3 Bank 1 Write */
-#define FORTE_POWERDOWN         0x70    /* Blocks Power Down Control */
-
-#define FORTE_CAP_OFFSET        FORTE_CAP_CTRL - FORTE_PLY_CTRL
-
-#define FORTE_AC97_ADDR_SHIFT   10
-
-/* Playback and record control register bits */
-#define FORTE_BUF1_LAST         (1<<1)
-#define FORTE_BUF2_LAST         (1<<2)
-#define FORTE_START             (1<<5)
-#define FORTE_PAUSE             (1<<6)
-#define FORTE_IMMED_STOP        (1<<7)
-#define FORTE_RATE_SHIFT        8
-#define FORTE_RATE_MASK         (15 << FORTE_RATE_SHIFT)
-#define FORTE_CHANNELS_4        (1<<12) /* Playback only */
-#define FORTE_CHANNELS_6        (2<<12) /* Playback only */
-#define FORTE_CHANNELS_6MS      (3<<12) /* Playback only */
-#define FORTE_CHANNELS_MASK     (3<<12)
-#define FORTE_16BIT             (1<<14)
-#define FORTE_STEREO            (1<<15)
-
-/* IRQ status bits */
-#define FORTE_IRQ_PLAYBACK      (1<<8)
-#define FORTE_IRQ_CAPTURE       (1<<9)
-#define FORTE_IRQ_VOLUME        (1<<14)
-#define FORTE_IRQ_MPU           (1<<15)
-
-/* CODEC control */
-#define FORTE_CC_CODEC_RESET    (1<<5)
-#define FORTE_CC_AC97_RESET     (1<<6)
-
-/* AC97 cmd */
-#define FORTE_AC97_WRITE        (0<<7)
-#define FORTE_AC97_READ         (1<<7)
-#define FORTE_AC97_DP_INVALID   (0<<8)
-#define FORTE_AC97_DP_VALID     (1<<8)
-#define FORTE_AC97_PORT_RDY     (0<<9)
-#define FORTE_AC97_PORT_BSY     (1<<9)
-
-
-struct forte_channel {
-        const char 		*name;
-
-	unsigned short		ctrl; 		/* Ctrl BAR contents */
-	unsigned long 		iobase;		/* Ctrl BAR address */
-
-	wait_queue_head_t	wait;
-
-	void 			*buf; 		/* Buffer */
-	dma_addr_t		buf_handle; 	/* Buffer handle */
-
-        unsigned int 		record;
-	unsigned int		format;
-        unsigned int		rate;
-	unsigned int		stereo;
-
-	unsigned int		frag_sz; 	/* Current fragment size */
-	unsigned int		frag_num; 	/* Current # of fragments */
-	unsigned int		frag_msecs;     /* Milliseconds per frag */
-	unsigned int		buf_sz;		/* Current buffer size */
-
-	unsigned int		hwptr;		/* Tail */
-	unsigned int		swptr; 		/* Head */
-	unsigned int		filled_frags; 	/* Fragments currently full */
-	unsigned int		next_buf;	/* Index of next buffer */
-
-	unsigned int		active;		/* Channel currently in use */
-	unsigned int		mapped;		/* mmap */
-
-	unsigned int		buf_pages;	/* Real size of buffer */
-	unsigned int		nr_irqs;	/* Number of interrupts */
-	unsigned int		bytes;		/* Total bytes */
-	unsigned int		residue;	/* Partial fragment */
-};
-
-
-struct forte_chip {
-	struct pci_dev		*pci_dev;
-	unsigned long		iobase;
-	int			irq;
-
-	struct mutex		open_mutex; 	/* Device access */
-	spinlock_t		lock;		/* State */
-
-	spinlock_t		ac97_lock;
-	struct ac97_codec	*ac97;
-
-	int			multichannel;
-	int			dsp; 		/* OSS handle */
-	int                     trigger;	/* mmap I/O trigger */
-
-	struct forte_channel	play;
-	struct forte_channel	rec;
-};
-
-
-static int channels[] = { 2, 4, 6, };
-static int rates[]    = { 5500, 8000, 9600, 11025, 16000, 19200, 
-			  22050, 32000, 38400, 44100, 48000, };
-
-static struct forte_chip *forte;
-static int found;
-
-
-/* AC97 Codec -------------------------------------------------------------- */
-
-
-/** 
- * forte_ac97_wait:
- * @chip:	fm801 instance whose AC97 codec to wait on
- *
- * FIXME:
- *		Stop busy-waiting
- */
-
-static inline int
-forte_ac97_wait (struct forte_chip *chip)
-{
-	int i = 10000;
-
-	while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY) 
-		&& i-- )
-		cpu_relax();
-
-	return i == 0;
-}
-
-
-/**
- * forte_ac97_read:
- * @codec:	AC97 codec to read from
- * @reg:	register to read
- */
-
-static u16
-forte_ac97_read (struct ac97_codec *codec, u8 reg)
-{
-	u16 ret = 0;
-	struct forte_chip *chip = codec->private_data;
-
-	spin_lock (&chip->ac97_lock);
-
-	/* Knock, knock */
-	if (forte_ac97_wait (chip)) {
-		printk (KERN_ERR PFX "ac97_read: Serial bus busy\n");
-		goto out;
-	}
-
-	/* Send read command */
-	outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD);
-
-	if (forte_ac97_wait (chip)) {
-		printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n",
-			reg);
-		goto out;
-	}
-	
-	/* Sanity checking */
-	if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) {
-		printk (KERN_ERR PFX "ac97_read: Invalid data port");
-		goto out;
-	}
-
-	/* Fetch result */
-	ret = inw (chip->iobase + FORTE_AC97_DATA);
-
- out:
-	spin_unlock (&chip->ac97_lock);
-	return ret;
-}
-
-
-/**
- * forte_ac97_write:
- * @codec:	AC97 codec to send command to
- * @reg:	register to write
- * @val:	value to write
- */
-
-static void
-forte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val)
-{
-	struct forte_chip *chip = codec->private_data;
-
-	spin_lock (&chip->ac97_lock);
-
-	/* Knock, knock */
-	if (forte_ac97_wait (chip)) {
-		printk (KERN_ERR PFX "ac97_write: Serial bus busy\n");
-		goto out;
-	}
-
-	outw (val, chip->iobase + FORTE_AC97_DATA);
-	outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD);
-
-	/* Wait for completion */
-	if (forte_ac97_wait (chip)) {
-		printk (KERN_ERR PFX "ac97_write: Bus busy after write\n");
-		goto out;
-	}
-
- out:
-	spin_unlock (&chip->ac97_lock);
-}
-
-
-/* Mixer ------------------------------------------------------------------- */
-
-
-/**
- * forte_mixer_open:
- * @inode:		
- * @file:		
- */
-
-static int
-forte_mixer_open (struct inode *inode, struct file *file)
-{
-	struct forte_chip *chip = forte;
-	file->private_data = chip->ac97;
-	return 0;
-}
-
-
-/**
- * forte_mixer_release:
- * @inode:		
- * @file:		
- */
-
-static int
-forte_mixer_release (struct inode *inode, struct file *file)
-{
-	/* We will welease Wodewick */
-	return 0;
-}
-
-
-/**
- * forte_mixer_ioctl:
- * @inode:		
- * @file:		
- */
-
-static int
-forte_mixer_ioctl (struct inode *inode, struct file *file, 
-		   unsigned int cmd, unsigned long arg)
-{
-	struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
-
-	return codec->mixer_ioctl (codec, cmd, arg);
-}
-
-
-static struct file_operations forte_mixer_fops = {
-	.owner			= THIS_MODULE,
-	.llseek         	= no_llseek,
-	.ioctl          	= forte_mixer_ioctl,
-	.open           	= forte_mixer_open,
-	.release        	= forte_mixer_release,
-};
-
-
-/* Channel ----------------------------------------------------------------- */
-
-/** 
- * forte_channel_reset:
- * @channel:	Channel to reset
- * 
- * Locking:	Must be called with lock held.
- */
-
-static void
-forte_channel_reset (struct forte_channel *channel)
-{
-	if (!channel || !channel->iobase)
-		return;
-
-	DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);
-
-	channel->ctrl &= ~FORTE_START;
-	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-	
-	/* We always play at least two fragments, hence these defaults */
- 	channel->hwptr = channel->frag_sz;
-	channel->next_buf = 1;
-	channel->swptr = 0;
-	channel->filled_frags = 0;
-	channel->active = 0;
-	channel->bytes = 0;
-	channel->nr_irqs = 0;
-	channel->mapped = 0;
-	channel->residue = 0;
-}
-
-
-/** 
- * forte_channel_start:
- * @channel: 	Channel to start (record/playback)
- *
- * Locking:	Must be called with lock held.
- */
-
-static void inline
-forte_channel_start (struct forte_channel *channel)
-{
-	if (!channel || !channel->iobase || channel->active) 
-		return;
-
-	channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST
-			   | FORTE_IMMED_STOP);
-	channel->ctrl |= FORTE_START;
-	channel->active = 1;
-	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/** 
- * forte_channel_stop:
- * @channel: 	Channel to stop
- *
- * Locking:	Must be called with lock held.
- */
-
-static void inline
-forte_channel_stop (struct forte_channel *channel)
-{
-	if (!channel || !channel->iobase) 
-		return;
-
-	channel->ctrl &= ~(FORTE_START | FORTE_PAUSE);	
-	channel->ctrl |= FORTE_IMMED_STOP;
-
-	channel->active = 0;
-	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/** 
- * forte_channel_pause:
- * @channel: 	Channel to pause
- *
- * Locking:	Must be called with lock held.
- */
-
-static void inline
-forte_channel_pause (struct forte_channel *channel)
-{
-	if (!channel || !channel->iobase) 
-		return;
-
-	channel->ctrl |= FORTE_PAUSE;
-
-	channel->active = 0;
-	outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/** 
- * forte_channel_rate:
- * @channel: 	Channel whose rate to set.  Playback and record are
- *           	independent.
- * @rate:    	Channel rate in Hz
- *
- * Locking:	Must be called with lock held.
- */
-
-static int
-forte_channel_rate (struct forte_channel *channel, unsigned int rate)
-{
-	int new_rate;
-
-	if (!channel || !channel->iobase) 
-		return -EINVAL;
-
-	/* The FM801 only supports a handful of fixed frequencies.
-	 * We find the value closest to what userland requested.
-	 */
-	if      (rate <= 6250)  { rate = 5500;  new_rate =  0; }
-	else if (rate <= 8800)  { rate = 8000;  new_rate =  1; }
-	else if (rate <= 10312) { rate = 9600;  new_rate =  2; }
-	else if (rate <= 13512) { rate = 11025; new_rate =  3; }
-	else if (rate <= 17600) { rate = 16000; new_rate =  4; }
-	else if (rate <= 20625) { rate = 19200; new_rate =  5; }
-	else if (rate <= 27025) { rate = 22050; new_rate =  6; }
-	else if (rate <= 35200) { rate = 32000; new_rate =  7; }
-	else if (rate <= 41250) { rate = 38400; new_rate =  8; }
-	else if (rate <= 46050) { rate = 44100; new_rate =  9; }
-	else                    { rate = 48000; new_rate = 10; }
-
-	channel->ctrl &= ~FORTE_RATE_MASK;
-	channel->ctrl |= new_rate << FORTE_RATE_SHIFT;
-	channel->rate = rate;
-
-	DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate);
-
-	return rate;
-}
-
-
-/** 
- * forte_channel_format:
- * @channel: 	Channel whose audio format to set
- * @format:  	OSS format ID
- *
- * Locking:	Must be called with lock held.
- */
-
-static int
-forte_channel_format (struct forte_channel *channel, int format)
-{
-	if (!channel || !channel->iobase) 
-		return -EINVAL;
-
-	switch (format) {
-
-	case AFMT_QUERY:
-		break;
-	
-	case AFMT_U8:
-		channel->ctrl &= ~FORTE_16BIT;
-		channel->format = AFMT_U8;
-		break;
-
-	case AFMT_S16_LE:
-	default:
-		channel->ctrl |= FORTE_16BIT;
-		channel->format = AFMT_S16_LE;
-		break;
-	}
-
-	DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name, 
-		 format, channel->format);
-
-	return channel->format;
-}
-
-
-/** 
- * forte_channel_stereo:
- * @channel: 	Channel to toggle
- * @stereo:  	0 for Mono, 1 for Stereo
- *
- * Locking:	Must be called with lock held.
- */
-
-static int
-forte_channel_stereo (struct forte_channel *channel, unsigned int stereo)
-{
-	int ret;
-
-	if (!channel || !channel->iobase)
-		return -EINVAL;
-
-	DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo);
-
-	switch (stereo) {
-
-	case 0:
-		channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK);
-		channel-> stereo = stereo;
-		ret = stereo;
-		break;
-
-	case 1:
-		channel->ctrl &= ~FORTE_CHANNELS_MASK;
-		channel->ctrl |= FORTE_STEREO;
-		channel-> stereo = stereo;
-		ret = stereo;
-		break;
-
-	default:
-		DPRINTK ("Unsupported channel format");
-		ret = -EINVAL;
-		break;
-	}
-
-	return ret;
-}
-
-
-/** 
- * forte_channel_buffer:
- * @channel:	Channel whose buffer to set up
- *
- * Locking:	Must be called with lock held.
- */
-
-static void
-forte_channel_buffer (struct forte_channel *channel, int sz, int num)
-{
-	unsigned int msecs, shift;
-
-	/* Go away, I'm busy */
-	if (channel->filled_frags || channel->bytes)
-		return;
-
-	/* Fragment size must be a power of 2 */
-	shift = 0; sz++;
-	while (sz >>= 1)
-		shift++;
-	channel->frag_sz = 1 << shift;
-
-	/* Round fragment size to something reasonable */
-	if (channel->frag_sz < FORTE_MIN_FRAG_SIZE)
-		channel->frag_sz = FORTE_MIN_FRAG_SIZE;
-
-	if (channel->frag_sz > FORTE_MAX_FRAG_SIZE)
-		channel->frag_sz = FORTE_MAX_FRAG_SIZE;
-
-	/* Find fragment length in milliseconds */
-	msecs = channel->frag_sz /
-		(channel->format == AFMT_S16_LE ? 2 : 1) /
-		(channel->stereo ? 2 : 1) /
-		(channel->rate / 1000);
-
-	channel->frag_msecs = msecs;
-
-	/* Pick a suitable number of fragments */
-	if (msecs * num < FORTE_MIN_BUF_MSECS)
-	     num = FORTE_MIN_BUF_MSECS / msecs;
-
-	if (msecs * num > FORTE_MAX_BUF_MSECS)
-	     num = FORTE_MAX_BUF_MSECS / msecs;
-
-	/* Fragment number must be a power of 2 */
-	shift = 0;	
-	while (num >>= 1)
-		shift++;
-	channel->frag_num = 1 << (shift + 1);
-
-	/* Round fragment number to something reasonable */
-	if (channel->frag_num < FORTE_MIN_FRAGMENTS)
-		channel->frag_num = FORTE_MIN_FRAGMENTS;
-
-	if (channel->frag_num > FORTE_MAX_FRAGMENTS)
-		channel->frag_num = FORTE_MAX_FRAGMENTS;
-
-	channel->buf_sz = channel->frag_sz * channel->frag_num;
-
-	DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n",
-		 __FUNCTION__, channel->name, channel->frag_sz, 
-		 channel->frag_num, channel->buf_sz);
-}
-
-
-/** 
- * forte_channel_prep:
- * @channel:	Channel whose buffer to prepare
- *
- * Locking:	Lock held.
- */
-
-static void
-forte_channel_prep (struct forte_channel *channel)
-{
-	struct page *page;
-	int i;
-	
-	if (channel->buf)
-		return;
-
-	forte_channel_buffer (channel, channel->frag_sz, channel->frag_num);
-	channel->buf_pages = channel->buf_sz >> PAGE_SHIFT;
-
-	if (channel->buf_sz % PAGE_SIZE)
-		channel->buf_pages++;
-
-	DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n", 
-		 __FUNCTION__, channel->name, channel->frag_sz, 
-		 channel->frag_num, channel->buf_sz, channel->buf_pages);
-
-	/* DMA buffer */
-	channel->buf = pci_alloc_consistent (forte->pci_dev, 
-					     channel->buf_pages * PAGE_SIZE,
-					     &channel->buf_handle);
-
-	if (!channel->buf || !channel->buf_handle)
-		BUG();
-
-	page = virt_to_page (channel->buf);
-	
-	/* FIXME: can this go away ? */
-	for (i = 0 ; i < channel->buf_pages ; i++)
-		SetPageReserved(page++);
-
-	/* Prep buffer registers */
-	outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT);
-	outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1);
-	outl (channel->buf_handle + channel->frag_sz, 
-	      channel->iobase + FORTE_PLY_BUF2);
-
-	/* Reset hwptr */
- 	channel->hwptr = channel->frag_sz;
-	channel->next_buf = 1;
-
-	DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name, 
-		 channel->buf, channel->buf_handle);
-}
-
-
-/** 
- * forte_channel_drain:
- * @chip:	
- * @channel:	
- *
- * Locking:	Don't hold the lock.
- */
-
-static inline int
-forte_channel_drain (struct forte_channel *channel)
-{
-	DECLARE_WAITQUEUE (wait, current);
-	unsigned long flags;
-
-	DPRINTK ("%s\n", __FUNCTION__);
-
-	if (channel->mapped) {
-		spin_lock_irqsave (&forte->lock, flags);
-		forte_channel_stop (channel);
-		spin_unlock_irqrestore (&forte->lock, flags);
-		return 0;
-	}
-
-	spin_lock_irqsave (&forte->lock, flags);
-	add_wait_queue (&channel->wait, &wait);
-
-	for (;;) {
-		if (channel->active == 0 || channel->filled_frags == 1)
-			break;
-
-		spin_unlock_irqrestore (&forte->lock, flags);
-
-		__set_current_state (TASK_INTERRUPTIBLE);
-		schedule();
-
-		spin_lock_irqsave (&forte->lock, flags);
-	}
-
-	forte_channel_stop (channel);
-	forte_channel_reset (channel);
-	set_current_state (TASK_RUNNING);
-	remove_wait_queue (&channel->wait, &wait);
-	spin_unlock_irqrestore (&forte->lock, flags);
-
-	return 0;
-}
-
-
-/** 
- * forte_channel_init:
- * @chip: 	Forte chip instance the channel hangs off
- * @channel: 	Channel to initialize
- *
- * Description:
- *	        Initializes a channel, sets defaults, and allocates
- *	        buffers.
- *
- * Locking:	No lock held.
- */
-
-static int
-forte_channel_init (struct forte_chip *chip, struct forte_channel *channel)
-{
-	DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase);
-
-	spin_lock_irq (&chip->lock);
-	memset (channel, 0x0, sizeof (*channel));
-
-	if (channel == &chip->play) {
-		channel->name = "PCM_OUT";
-		channel->iobase = chip->iobase;
-		DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__,
-			 (void *) channel->iobase);
-	}
-	else if (channel == &chip->rec) {
-		channel->name = "PCM_IN";
-		channel->iobase = chip->iobase + FORTE_CAP_OFFSET;
-		channel->record = 1;
-		DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__, 
-			 (void *) channel->iobase);
-	}
-	else
-		BUG();
-
-	init_waitqueue_head (&channel->wait);
-
-	/* Defaults: 48kHz, 16-bit, stereo */
-	channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL);
-	forte_channel_reset (channel);
-	forte_channel_stereo (channel, 1);
-	forte_channel_format (channel, AFMT_S16_LE);
-	forte_channel_rate (channel, 48000);
-	channel->frag_sz = FORTE_DEF_FRAG_SIZE;
-	channel->frag_num = FORTE_DEF_FRAGMENTS;
-
-	chip->trigger = 0;
-	spin_unlock_irq (&chip->lock);
-
-	return 0;
-}
-
-
-/** 
- * forte_channel_free:
- * @chip:	Chip this channel hangs off
- * @channel:	Channel to nuke 
- *
- * Description:
- * 		Resets channel and frees buffers.
- *
- * Locking:	Hold your horses.
- */
-
-static void
-forte_channel_free (struct forte_chip *chip, struct forte_channel *channel)
-{
-	DPRINTK ("%s: %s\n", __FUNCTION__, channel->name);
-
-	if (!channel->buf_handle)
-		return;
-
-	pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE, 
-			     channel->buf, channel->buf_handle);
-	
-	memset (channel, 0x0, sizeof (*channel));
-}
-
-
-/* DSP --------------------------------------------------------------------- */
-
-
-/**
- * forte_dsp_ioctl:
- */
-
-static int
-forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
-		 unsigned long arg)
-{
-	int ival=0, ret, rval=0, rd, wr, count;
-	struct forte_chip *chip;
-	struct audio_buf_info abi;
-	struct count_info cinfo;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	chip = file->private_data;
-	
-	if (file->f_mode & FMODE_WRITE)
-		wr = 1;
-	else 
-		wr = 0;
-
-	if (file->f_mode & FMODE_READ)
-		rd = 1;
-	else
-		rd = 0;
-
-	switch (cmd) {
-
-	case OSS_GETVERSION:
-		return put_user (SOUND_VERSION, p);
-
-	case SNDCTL_DSP_GETCAPS:
-		DPRINTK ("%s: GETCAPS\n", __FUNCTION__);
-
-		ival = FORTE_CAPS; /* DUPLEX */
-		return put_user (ival, p);
-
-	case SNDCTL_DSP_GETFMTS:
-		DPRINTK ("%s: GETFMTS\n", __FUNCTION__);
-
-		ival = FORTE_FMTS; /* U8, 16LE */
-		return put_user (ival, p);
-
-	case SNDCTL_DSP_SETFMT:	/* U8, 16LE */
-		DPRINTK ("%s: SETFMT\n", __FUNCTION__);
-
-		if (get_user (ival, p))
-			return -EFAULT;
-
-		spin_lock_irq (&chip->lock);
-
-		if (rd) {
-			forte_channel_stop (&chip->rec);
-			rval = forte_channel_format (&chip->rec, ival);
-		}
-
-		if (wr) {
-			forte_channel_stop (&chip->rec);
-			rval = forte_channel_format (&chip->play, ival);
-		}
-
-		spin_unlock_irq (&chip->lock);
-	
-		return put_user (rval, p);
-
-	case SNDCTL_DSP_STEREO:	/* 0 - mono, 1 - stereo */
-		DPRINTK ("%s: STEREO\n", __FUNCTION__);
-
-		if (get_user (ival, p))
-			return -EFAULT;
-
-		spin_lock_irq (&chip->lock);
-
-		if (rd) {
-			forte_channel_stop (&chip->rec);
-			rval = forte_channel_stereo (&chip->rec, ival);
-		}
-
-		if (wr) {
-			forte_channel_stop (&chip->rec);
-			rval = forte_channel_stereo (&chip->play, ival);
-		}
-
-		spin_unlock_irq (&chip->lock);
-
-                return put_user (rval, p);
-
-	case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */
-		DPRINTK ("%s: CHANNELS\n", __FUNCTION__);
-
-		if (get_user (ival, p))
-			return -EFAULT;
-
-		spin_lock_irq (&chip->lock);
-
-		if (rd) {
-			forte_channel_stop (&chip->rec);
-			rval = forte_channel_stereo (&chip->rec, ival-1) + 1;
-		}
-
-		if (wr) {
-			forte_channel_stop (&chip->play);
-			rval = forte_channel_stereo (&chip->play, ival-1) + 1;
-		}
-
-		spin_unlock_irq (&chip->lock);
-
-                return put_user (rval, p);
-
-	case SNDCTL_DSP_SPEED:
-		DPRINTK ("%s: SPEED\n", __FUNCTION__);
-
-		if (get_user (ival, p))
-                        return -EFAULT;
-
-		spin_lock_irq (&chip->lock);
-
-		if (rd) {
-			forte_channel_stop (&chip->rec);
-			rval = forte_channel_rate (&chip->rec, ival);
-		}
-
-		if (wr) {
-			forte_channel_stop (&chip->play);
-			rval = forte_channel_rate (&chip->play, ival);
-		}
-
-		spin_unlock_irq (&chip->lock);
-
-                return put_user(rval, p);
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__);
-
-		spin_lock_irq (&chip->lock);
-
-		if (rd)
-			ival = chip->rec.frag_sz;
-
-		if (wr)
-			ival = chip->play.frag_sz;
-
-		spin_unlock_irq (&chip->lock);
-
-                return put_user (ival, p);
-
-	case SNDCTL_DSP_RESET:
-		DPRINTK ("%s: RESET\n", __FUNCTION__);
-
-		spin_lock_irq (&chip->lock);
-
-		if (rd)
-			forte_channel_reset (&chip->rec);
-
-		if (wr)
-			forte_channel_reset (&chip->play);
-
-		spin_unlock_irq (&chip->lock);
-
-                return 0;
-
-	case SNDCTL_DSP_SYNC:
-		DPRINTK ("%s: SYNC\n", __FUNCTION__);
-
-		if (wr)
-			ret = forte_channel_drain (&chip->play);
-
-		return 0;
-
-	case SNDCTL_DSP_POST:
-		DPRINTK ("%s: POST\n", __FUNCTION__);
-
-		if (wr) {
-			spin_lock_irq (&chip->lock);
-
-			if (chip->play.filled_frags)
-				forte_channel_start (&chip->play);
-
-			spin_unlock_irq (&chip->lock);
-		}
-
-                return 0;
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__);
-
-		if (get_user (ival, p))
-			return -EFAULT;
-
-		spin_lock_irq (&chip->lock);
-
-		if (rd) {
-			forte_channel_buffer (&chip->rec, ival & 0xffff, 
-					      (ival >> 16) & 0xffff);
-			ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz;
-		}
-
-		if (wr) {
-			forte_channel_buffer (&chip->play, ival & 0xffff, 
-					      (ival >> 16) & 0xffff);
-			ival = (chip->play.frag_num << 16) +chip->play.frag_sz;
-		}
-
-		spin_unlock_irq (&chip->lock);
-
-		return put_user (ival, p);
-                
-        case SNDCTL_DSP_GETISPACE:
-		DPRINTK ("%s: GETISPACE\n", __FUNCTION__);
-
-		if (!rd)
-			return -EINVAL;
-
-		spin_lock_irq (&chip->lock);
-
-		abi.fragstotal = chip->rec.frag_num;
-		abi.fragsize = chip->rec.frag_sz;
-			
-		if (chip->rec.mapped) {
-			abi.fragments = chip->rec.frag_num - 2;
-			abi.bytes = abi.fragments * abi.fragsize;
-		}
-		else {
-			abi.fragments = chip->rec.filled_frags;
-			abi.bytes = abi.fragments * abi.fragsize;
-		}
-
-		spin_unlock_irq (&chip->lock);
-
-		return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETIPTR:
-		DPRINTK ("%s: GETIPTR\n", __FUNCTION__);
-
-		if (!rd)
-			return -EINVAL;
-
-		spin_lock_irq (&chip->lock);
-
-		if (chip->rec.active) 
-			cinfo.ptr = chip->rec.hwptr;
-		else
-			cinfo.ptr = 0;
-
-		cinfo.bytes = chip->rec.bytes;
-		cinfo.blocks = chip->rec.nr_irqs;
-		chip->rec.nr_irqs = 0;
-
-		spin_unlock_irq (&chip->lock);
-
-		return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
-
-        case SNDCTL_DSP_GETOSPACE:
-		if (!wr)
-			return -EINVAL;
-		
-		spin_lock_irq (&chip->lock);
-
-		abi.fragstotal = chip->play.frag_num;
-		abi.fragsize = chip->play.frag_sz;
-
-		if (chip->play.mapped) {
-			abi.fragments = chip->play.frag_num - 2;
-			abi.bytes = chip->play.buf_sz;
-		}
-		else {
-			abi.fragments = chip->play.frag_num - 
-				chip->play.filled_frags;
-
-			if (chip->play.residue)
-				abi.fragments--;
-
-			abi.bytes = abi.fragments * abi.fragsize +
-				chip->play.residue;
-		}
-
-		spin_unlock_irq (&chip->lock);
-		
-		return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETOPTR:
-		if (!wr)
-			return -EINVAL;
-
-		spin_lock_irq (&chip->lock);
-
-		if (chip->play.active) 
-			cinfo.ptr = chip->play.hwptr;
-		else
-			cinfo.ptr = 0;
-
-		cinfo.bytes = chip->play.bytes;
-		cinfo.blocks = chip->play.nr_irqs;
-		chip->play.nr_irqs = 0;
-
-		spin_unlock_irq (&chip->lock);
-
-		return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETODELAY:
-		if (!wr)
-			return -EINVAL;
-
-		spin_lock_irq (&chip->lock);
-
-		if (!chip->play.active) {
-			ival = 0;
-		}
-		else if (chip->play.mapped) {
-			count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1;
-			ival = chip->play.frag_sz - count;
-		}
-		else {
-			ival = chip->play.filled_frags * chip->play.frag_sz;
-
-			if (chip->play.residue)
-				ival += chip->play.frag_sz - chip->play.residue;
-		}
-
-		spin_unlock_irq (&chip->lock);
-
-		return put_user (ival, p);
-
-	case SNDCTL_DSP_SETDUPLEX:
-		DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__);
-
-		return -EINVAL;
-
-	case SNDCTL_DSP_GETTRIGGER:
-		DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__);
-		
-		return put_user (chip->trigger, p);
-		
-	case SNDCTL_DSP_SETTRIGGER:
-
-		if (get_user (ival, p))
-			return -EFAULT;
-
-		DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival);
-
-		if (wr) {
-			spin_lock_irq (&chip->lock);
-
-			if (ival & PCM_ENABLE_OUTPUT)
-				forte_channel_start (&chip->play);
-			else {		
-				chip->trigger = 1;
-				forte_channel_prep (&chip->play);
-				forte_channel_stop (&chip->play);
-			}
-
-			spin_unlock_irq (&chip->lock);
-		}
-		else if (rd) {
-			spin_lock_irq (&chip->lock);
-
-			if (ival & PCM_ENABLE_INPUT)
-				forte_channel_start (&chip->rec);
-			else {		
-				chip->trigger = 1;
-				forte_channel_prep (&chip->rec);
-				forte_channel_stop (&chip->rec);
-			}
-
-			spin_unlock_irq (&chip->lock);
-		}
-
-		return 0;
-		
-	case SOUND_PCM_READ_RATE:
-		DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__);		
-		return put_user (chip->play.rate, p);
-
-	case SOUND_PCM_READ_CHANNELS:
-		DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__);
-		return put_user (chip->play.stereo, p);
-
-	case SOUND_PCM_READ_BITS:
-		DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__);		
-		return put_user (chip->play.format, p);
-
-	case SNDCTL_DSP_NONBLOCK:
-		DPRINTK ("%s: DSP_NONBLOCK\n", __FUNCTION__);		
-                file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	default:
-		DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, argp);
-		break;
-	}
-
-	return -EINVAL;
-}
-
-
-/**
- * forte_dsp_open:
- */
-
-static int 
-forte_dsp_open (struct inode *inode, struct file *file)
-{
-	struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */
-
-	if (file->f_flags & O_NONBLOCK) {
-		if (!mutex_trylock(&chip->open_mutex)) {
-			DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__);
-			return -EAGAIN;
-		}
-	}
-	else {
-		if (mutex_lock_interruptible(&chip->open_mutex)) {
-			DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
-			return -ERESTARTSYS;
-		}
-	}
-
-	file->private_data = forte;
-
-	DPRINTK ("%s: dsp opened by %d\n", __FUNCTION__, current->pid);
-
-	if (file->f_mode & FMODE_WRITE)
-		forte_channel_init (forte, &forte->play);
-
-	if (file->f_mode & FMODE_READ)
-		forte_channel_init (forte, &forte->rec);
-
-	return nonseekable_open(inode, file);
-}
-
-
-/**
- * forte_dsp_release:
- */
-
-static int 
-forte_dsp_release (struct inode *inode, struct file *file)
-{
-	struct forte_chip *chip = file->private_data;
-	int ret = 0;
-
-	DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip);
-
-	if (file->f_mode & FMODE_WRITE) {
-		forte_channel_drain (&chip->play);
-
-		spin_lock_irq (&chip->lock);
-
- 		forte_channel_free (chip, &chip->play);
-
-		spin_unlock_irq (&chip->lock);
-        }
-
-	if (file->f_mode & FMODE_READ) {
-		while (chip->rec.filled_frags > 0)
-			interruptible_sleep_on (&chip->rec.wait);
-
-		spin_lock_irq (&chip->lock);
-
-		forte_channel_stop (&chip->rec);
-		forte_channel_free (chip, &chip->rec);
-
-		spin_unlock_irq (&chip->lock);
-	}
-
-	mutex_unlock(&chip->open_mutex);
-
-	return ret;
-}
-
-
-/**
- * forte_dsp_poll:
- *
- */
-
-static unsigned int 
-forte_dsp_poll (struct file *file, struct poll_table_struct *wait)
-{
-	struct forte_chip *chip;
-	struct forte_channel *channel;
-	unsigned int mask = 0;
-
-	chip = file->private_data;
-
-	if (file->f_mode & FMODE_WRITE) {
-		channel = &chip->play;
-
-		if (channel->active)
-			poll_wait (file, &channel->wait, wait);
-
-		spin_lock_irq (&chip->lock);
-
-		if (channel->frag_num - channel->filled_frags > 0)
-			mask |= POLLOUT | POLLWRNORM;
-
-		spin_unlock_irq (&chip->lock);
-	}
-
-	if (file->f_mode & FMODE_READ) {
-		channel = &chip->rec;
-
-		if (channel->active)
-			poll_wait (file, &channel->wait, wait);
-
-		spin_lock_irq (&chip->lock);
-
-		if (channel->filled_frags > 0)
-			mask |= POLLIN | POLLRDNORM;
-
-		spin_unlock_irq (&chip->lock);
-	}
-
-	return mask;
-}
-
-
-/**
- * forte_dsp_mmap:
- */
-
-static int
-forte_dsp_mmap (struct file *file, struct vm_area_struct *vma)
-{
-	struct forte_chip *chip;
-	struct forte_channel *channel;
-	unsigned long size;
-	int ret;
-
-	chip = file->private_data;
-
-	DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__,
-                 vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff);
-
-	spin_lock_irq (&chip->lock);
-
-	if (vma->vm_flags & VM_WRITE && chip->play.active) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-        if (vma->vm_flags & VM_READ && chip->rec.active) {
-		ret = -EBUSY;
-		goto out;
-        }
-
-	if (file->f_mode & FMODE_WRITE)
-		channel = &chip->play;
-	else if (file->f_mode & FMODE_READ)
-		channel = &chip->rec;
-	else {
-		ret = -EINVAL;
-		goto out;
-	}
-
-	forte_channel_prep (channel);
-	channel->mapped = 1;
-
-        if (vma->vm_pgoff != 0) {
-		ret = -EINVAL;
-                goto out;
-	}
-
-        size = vma->vm_end - vma->vm_start;
-
-        if (size > channel->buf_pages * PAGE_SIZE) {
-		DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__,
-			 size, channel->buf_sz);
-		ret = -EINVAL;
-                goto out;
-	}
-
-        if (remap_pfn_range(vma, vma->vm_start,
-			      virt_to_phys(channel->buf) >> PAGE_SHIFT,
-			      size, vma->vm_page_prot)) {
-		DPRINTK ("%s: remap el a no worko\n", __FUNCTION__);
-		ret = -EAGAIN;
-                goto out;
-	}
-
-        ret = 0;
-
- out:
-	spin_unlock_irq (&chip->lock);
-        return ret;
-}
-
-
-/**
- * forte_dsp_write:
- */
-
-static ssize_t 
-forte_dsp_write (struct file *file, const char __user *buffer, size_t bytes, 
-		 loff_t *ppos)
-{
-	struct forte_chip *chip;
-	struct forte_channel *channel;
-	unsigned int i = bytes, sz = 0;
-	unsigned long flags;
-
-	if (!access_ok (VERIFY_READ, buffer, bytes))
-		return -EFAULT;
-
-	chip = (struct forte_chip *) file->private_data;
-
-	if (!chip)
-		BUG();
-
-	channel = &chip->play;
-
-	if (!channel)
-		BUG();
-
-	spin_lock_irqsave (&chip->lock, flags);
-
-	/* Set up buffers with the right fragment size */
-	forte_channel_prep (channel);
-
-	while (i) {
-		/* All fragment buffers in use -> wait */
-		if (channel->frag_num - channel->filled_frags == 0) {
-			DECLARE_WAITQUEUE (wait, current);
-
-			/* For trigger or non-blocking operation, get out */
-			if (chip->trigger || file->f_flags & O_NONBLOCK) {
-				spin_unlock_irqrestore (&chip->lock, flags);
-				return -EAGAIN;
-			}
-
-			/* Otherwise wait for buffers */
-			add_wait_queue (&channel->wait, &wait);
-
-			for (;;) {
-				spin_unlock_irqrestore (&chip->lock, flags);
-
-				set_current_state (TASK_INTERRUPTIBLE);
-				schedule();
-
-				spin_lock_irqsave (&chip->lock, flags);
-
-				if (channel->frag_num - channel->filled_frags)
-					break;
-			}
-
-			remove_wait_queue (&channel->wait, &wait);
-			set_current_state (TASK_RUNNING);
-
-			if (signal_pending (current)) {
-				spin_unlock_irqrestore (&chip->lock, flags);
-				return -ERESTARTSYS;
-			}
-		}
-
-		if (channel->residue)
-			sz = channel->residue;
-		else if (i > channel->frag_sz)
-			sz = channel->frag_sz;
-		else
-			sz = i;
-
-		spin_unlock_irqrestore (&chip->lock, flags);
-
-		if (copy_from_user ((void *) channel->buf + channel->swptr, buffer, sz))
-			return -EFAULT;
-
-		spin_lock_irqsave (&chip->lock, flags);
-
-		/* Advance software pointer */
-		buffer += sz;
-		channel->swptr += sz;
-		channel->swptr %= channel->buf_sz;
-		i -= sz;
-
-		/* Only bump filled_frags if a full fragment has been written */
-		if (channel->swptr % channel->frag_sz == 0) {
-			channel->filled_frags++;
-			channel->residue = 0;
-		}
-		else
-			channel->residue = channel->frag_sz - sz;
-
-		/* If playback isn't active, start it */
-		if (channel->active == 0 && chip->trigger == 0)
-			forte_channel_start (channel);
-	}
-
-	spin_unlock_irqrestore (&chip->lock, flags);
-
-	return bytes - i;
-}
-
-
-/**
- * forte_dsp_read:
- */
-
-static ssize_t 
-forte_dsp_read (struct file *file, char __user *buffer, size_t bytes, 
-		loff_t *ppos)
-{
-	struct forte_chip *chip;
-	struct forte_channel *channel;
-	unsigned int i = bytes, sz;
-	unsigned long flags;
-
-	if (!access_ok (VERIFY_WRITE, buffer, bytes))
-		return -EFAULT;
-
-	chip = (struct forte_chip *) file->private_data;
-
-	if (!chip)
-		BUG();
-
-	channel = &chip->rec;
-
-	if (!channel)
-		BUG();
-
-	spin_lock_irqsave (&chip->lock, flags);
-
-	/* Set up buffers with the right fragment size */
-	forte_channel_prep (channel);
-
-	/* Start recording */
-	if (!chip->trigger)
-		forte_channel_start (channel);
-
-	while (i) {
-		/* No fragment buffers in use -> wait */
-		if (channel->filled_frags == 0) {
-			DECLARE_WAITQUEUE (wait, current);
-
-			/* For trigger mode operation, get out */
-			if (chip->trigger) {
-				spin_unlock_irqrestore (&chip->lock, flags);
-				return -EAGAIN;
-			}
-
-			add_wait_queue (&channel->wait, &wait);
-
-			for (;;) {
-				if (channel->active == 0)
-					break;
-
-				if (channel->filled_frags)
-					break;
-						
-				spin_unlock_irqrestore (&chip->lock, flags);
-
-				set_current_state (TASK_INTERRUPTIBLE);
-				schedule();
-
-				spin_lock_irqsave (&chip->lock, flags);
-			}
-
-			set_current_state (TASK_RUNNING);
-			remove_wait_queue (&channel->wait, &wait);
-		}
-
-		if (i > channel->frag_sz)
-			sz = channel->frag_sz;
-		else
-			sz = i;
-
-		spin_unlock_irqrestore (&chip->lock, flags);
-
-		if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) {
-			DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__);
-			return -EFAULT;
-		}
-
-		spin_lock_irqsave (&chip->lock, flags);
-
-		/* Advance software pointer */
-		buffer += sz;
-		if (channel->filled_frags > 0)
-			channel->filled_frags--;
-		channel->swptr += channel->frag_sz;
-		channel->swptr %= channel->buf_sz;
-		i -= sz;
-	}
-
-	spin_unlock_irqrestore (&chip->lock, flags);
-
-	return bytes - i;
-}
-
-
-static struct file_operations forte_dsp_fops = {
-	.owner			= THIS_MODULE,
-	.llseek     		= &no_llseek,
-	.read       		= &forte_dsp_read,
-	.write      		= &forte_dsp_write,
-	.poll       		= &forte_dsp_poll,
-	.ioctl      		= &forte_dsp_ioctl,
-	.open       		= &forte_dsp_open,
-	.release    		= &forte_dsp_release,
-	.mmap			= &forte_dsp_mmap,
-};
-
-
-/* Common ------------------------------------------------------------------ */
-
-
-/**
- * forte_interrupt:
- */
-
-static irqreturn_t
-forte_interrupt (int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct forte_chip *chip = dev_id;
-	struct forte_channel *channel = NULL;
-	u16 status, count; 
-
-	status = inw (chip->iobase + FORTE_IRQ_STATUS);
-
-	/* If this is not for us, get outta here ASAP */
-	if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0)
-		return IRQ_NONE;
-	
-	if (status & FORTE_IRQ_PLAYBACK) {
-		channel = &chip->play;
-
-		spin_lock (&chip->lock);
-
-		if (channel->frag_sz == 0)
-			goto pack;
-
-		/* Declare a fragment done */
-		if (channel->filled_frags > 0)
-			channel->filled_frags--;
-		channel->bytes += channel->frag_sz;
-		channel->nr_irqs++;
-		
-		/* Flip-flop between buffer I and II */
-		channel->next_buf ^= 1;
-
-		/* Advance hardware pointer by fragment size and wrap around */
-		channel->hwptr += channel->frag_sz;
-		channel->hwptr %= channel->buf_sz;
-
-		/* Buffer I or buffer II BAR */
-                outl (channel->buf_handle + channel->hwptr, 
-		      channel->next_buf == 0 ?
-		      channel->iobase + FORTE_PLY_BUF1 :
-		      channel->iobase + FORTE_PLY_BUF2);
-
-		/* If the currently playing fragment is last, schedule pause */
-		if (channel->filled_frags == 1) 
-			forte_channel_pause (channel);
-
-	pack:
-		/* Acknowledge interrupt */
-                outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS);
-
-		if (waitqueue_active (&channel->wait)) 
-			wake_up_all (&channel->wait);
-
-		spin_unlock (&chip->lock);
-	}
-
-	if (status & FORTE_IRQ_CAPTURE) {
-		channel = &chip->rec;
-		spin_lock (&chip->lock);
-
-		/* One fragment filled */
-		channel->filled_frags++;
-
-		/* Get # of completed bytes */
-		count = inw (channel->iobase + FORTE_PLY_COUNT) + 1;
-
-		if (count == 0) {
-			DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__,
-				 channel->filled_frags);
-			channel->filled_frags = 0;
-			goto rack;
-		}
-
-		/* Buffer I or buffer II BAR */
-                outl (channel->buf_handle + channel->hwptr, 
-		      channel->next_buf == 0 ?
-		      channel->iobase + FORTE_PLY_BUF1 :
-		      channel->iobase + FORTE_PLY_BUF2);
-
-		/* Flip-flop between buffer I and II */
-		channel->next_buf ^= 1;
-
-		/* Advance hardware pointer by fragment size and wrap around */
-		channel->hwptr += channel->frag_sz;
-		channel->hwptr %= channel->buf_sz;
-
-		/* Out of buffers */
-		if (channel->filled_frags == channel->frag_num - 1)
-			forte_channel_stop (channel);
-	rack:
-		/* Acknowledge interrupt */
-                outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS);
-
-		spin_unlock (&chip->lock);
-
-		if (waitqueue_active (&channel->wait))
-			wake_up_all (&channel->wait);		
-	}
-
-	return IRQ_HANDLED;
-}
-
-
-/**
- * forte_proc_read:
- */
-
-static int
-forte_proc_read (char *page, char **start, off_t off, int count, 
-		 int *eof, void *data)
-{
-	int i = 0, p_rate, p_chan, r_rate;
-	unsigned short p_reg, r_reg;
-
-	i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n \n", 
-		      DRIVER_VERSION);
-
-	if (!forte->iobase)
-		return i;
-
-	p_rate = p_chan = -1;
-	p_reg  = inw (forte->iobase + FORTE_PLY_CTRL);
-	p_rate = (p_reg >> 8) & 15;
-	p_chan = (p_reg >> 12) & 3;
-
- 	if (p_rate >= 0 || p_rate <= 10)
-		p_rate = rates[p_rate];
-
-	if (p_chan >= 0 || p_chan <= 2)
-		p_chan = channels[p_chan];
-
-	r_rate = -1;
-	r_reg  = inw (forte->iobase + FORTE_CAP_CTRL);
-	r_rate = (r_reg >> 8) & 15;
-
- 	if (r_rate >= 0 || r_rate <= 10)
-		r_rate = rates[r_rate]; 
-
-	i += sprintf (page + i,
-		      "             Playback  Capture\n"
-		      "FIFO empty : %-3s       %-3s\n"
-		      "Buf1 Last  : %-3s       %-3s\n"
-		      "Buf2 Last  : %-3s       %-3s\n"
-		      "Started    : %-3s       %-3s\n"
-		      "Paused     : %-3s       %-3s\n"
-		      "Immed Stop : %-3s       %-3s\n"
-		      "Rate       : %-5d     %-5d\n"
-		      "Channels   : %-5d     -\n"
-		      "16-bit     : %-3s       %-3s\n"
-		      "Stereo     : %-3s       %-3s\n"
-		      " \n"
-		      "Buffer Sz  : %-6d    %-6d\n"
-		      "Frag Sz    : %-6d    %-6d\n"
-		      "Frag Num   : %-6d    %-6d\n"
-		      "Frag msecs : %-6d    %-6d\n"
-		      "Used Frags : %-6d    %-6d\n"
-		      "Mapped     : %-3s       %-3s\n",
-		      p_reg & 1<<0  ? "yes" : "no",
-		      r_reg & 1<<0  ? "yes" : "no",
-		      p_reg & 1<<1  ? "yes" : "no",
-		      r_reg & 1<<1  ? "yes" : "no",
-		      p_reg & 1<<2  ? "yes" : "no",
-		      r_reg & 1<<2  ? "yes" : "no",
-		      p_reg & 1<<5  ? "yes" : "no",
-		      r_reg & 1<<5  ? "yes" : "no",
-		      p_reg & 1<<6  ? "yes" : "no",
-		      r_reg & 1<<6  ? "yes" : "no",
-		      p_reg & 1<<7  ? "yes" : "no",
-		      r_reg & 1<<7  ? "yes" : "no",
-		      p_rate, r_rate,
-		      p_chan,
-		      p_reg & 1<<14 ? "yes" : "no",
-		      r_reg & 1<<14 ? "yes" : "no",
-		      p_reg & 1<<15 ? "yes" : "no",
-		      r_reg & 1<<15 ? "yes" : "no",
-		      forte->play.buf_sz,       forte->rec.buf_sz,
-		      forte->play.frag_sz,      forte->rec.frag_sz,
-		      forte->play.frag_num,     forte->rec.frag_num,
-		      forte->play.frag_msecs,   forte->rec.frag_msecs,
-		      forte->play.filled_frags, forte->rec.filled_frags,
-		      forte->play.mapped ? "yes" : "no",
-		      forte->rec.mapped ? "yes" : "no"
-		);
-
-	return i;
-}
-
-
-/**
- * forte_proc_init:
- *
- * Creates driver info entries in /proc
- */
-
-static int __init 
-forte_proc_init (void)
-{
-	if (!proc_mkdir ("driver/forte", NULL))
-		return -EIO;
-
-	if (!create_proc_read_entry ("driver/forte/chip", 0, NULL, forte_proc_read, forte)) {
-		remove_proc_entry ("driver/forte", NULL);
-		return -EIO;
-	}
-
-	if (!create_proc_read_entry("driver/forte/ac97", 0, NULL, ac97_read_proc, forte->ac97)) {
-		remove_proc_entry ("driver/forte/chip", NULL);
-		remove_proc_entry ("driver/forte", NULL);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-
-/**
- * forte_proc_remove:
- *
- * Removes driver info entries in /proc
- */
-
-static void
-forte_proc_remove (void)
-{
-	remove_proc_entry ("driver/forte/ac97", NULL);
-	remove_proc_entry ("driver/forte/chip", NULL);
-	remove_proc_entry ("driver/forte", NULL);	
-}
-
-
-/**
- * forte_chip_init:
- * @chip:	Chip instance to initialize
- *
- * Description:
- * 		Resets chip, configures codec and registers the driver with
- * 		the sound subsystem.
- *
- * 		Press and hold Start for 8 secs, then switch on Run
- * 		and hold for 4 seconds.  Let go of Start.  Numbers
- * 		assume a properly oiled TWG.
- */
-
-static int __devinit
-forte_chip_init (struct forte_chip *chip)
-{
-	u8 revision;
-	u16 cmdw;
-	struct ac97_codec *codec;
-
-	pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision);
-
-	if (revision >= 0xB1) {
-		chip->multichannel = 1;
-		printk (KERN_INFO PFX "Multi-channel device detected.\n");
-	}
-
-	/* Reset chip */
-	outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET, 
-	      chip->iobase + FORTE_CODEC_CTRL);
-	udelay(100);
-	outw (0, chip->iobase + FORTE_CODEC_CTRL);
-
-	/* Request read from AC97 */
-	outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT), 
-	      chip->iobase + FORTE_AC97_CMD);
-	mdelay(750);
-
-	if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) {
-		printk (KERN_INFO PFX "AC97 codec not responding");
-		return -EIO;
-	}
-
-	/* Init volume */
-	outw (0x0808, chip->iobase + FORTE_PCM_VOL);
-	outw (0x9f1f, chip->iobase + FORTE_FM_VOL);
-	outw (0x8808, chip->iobase + FORTE_I2S_VOL);
-
-	/* I2S control - I2S mode */
-	outw (0x0003, chip->iobase + FORTE_I2S_MODE);
-
-	/* Interrupt setup - unmask PLAYBACK & CAPTURE */
-	cmdw = inw (chip->iobase + FORTE_IRQ_MASK);
-	cmdw &= ~0x0003;
-	outw (cmdw, chip->iobase + FORTE_IRQ_MASK);
-
-	/* Interrupt clear */
-	outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE, 
-	      chip->iobase + FORTE_IRQ_STATUS);
-
-	/* Set up the AC97 codec */
-	if ((codec = ac97_alloc_codec()) == NULL)
-		return -ENOMEM;
-	codec->private_data = chip;
-	codec->codec_read = forte_ac97_read;
-	codec->codec_write = forte_ac97_write;
-	codec->id = 0;
-
-	if (ac97_probe_codec (codec) == 0) {
-		printk (KERN_ERR PFX "codec probe failed\n");
-		ac97_release_codec(codec);
-		return -1;
-	}
-
-	/* Register mixer */
-	if ((codec->dev_mixer = 
-	     register_sound_mixer (&forte_mixer_fops, -1)) < 0) {
-		printk (KERN_ERR PFX "couldn't register mixer!\n");
-		ac97_release_codec(codec);
-		return -1;
-	}
-
-	chip->ac97 = codec;
-
-	/* Register DSP */
-	if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) {
-		printk (KERN_ERR PFX "couldn't register dsp!\n");
-		return -1;
-	}
-
-	/* Register with /proc */
-	if (forte_proc_init()) {
-		printk (KERN_ERR PFX "couldn't add entries to /proc!\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-
-/**
- * forte_probe:
- * @pci_dev:	PCI struct for probed device
- * @pci_id:	
- *
- * Description:
- *		Allocates chip instance, I/O region, and IRQ
- */
-static int __init 
-forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
-	struct forte_chip *chip;
-	int ret = 0;
-
-	/* FIXME: Support more than one chip */
-	if (found++)
-		return -EIO;
-
-	/* Ignition */
-	if (pci_enable_device (pci_dev))
-		return -EIO;
-
-	pci_set_master (pci_dev);
-
-	/* Allocate chip instance and configure */
-	forte = (struct forte_chip *) 
-		kmalloc (sizeof (struct forte_chip), GFP_KERNEL);
-	chip = forte;
-
-	if (chip == NULL) {
-		printk (KERN_WARNING PFX "Out of memory");
-		return -ENOMEM;
-	}
-
-	memset (chip, 0, sizeof (struct forte_chip));
-	chip->pci_dev = pci_dev;
-
-	mutex_init(&chip->open_mutex);
-	spin_lock_init (&chip->lock);
-	spin_lock_init (&chip->ac97_lock);
-
-	if (! request_region (pci_resource_start (pci_dev, 0),
-			      pci_resource_len (pci_dev, 0), DRIVER_NAME)) {
-		printk (KERN_WARNING PFX "Unable to reserve I/O space");
-		ret = -ENOMEM;
-		goto error;
-	}
-
-	chip->iobase = pci_resource_start (pci_dev, 0);
-	chip->irq = pci_dev->irq;
-
-	if (request_irq (chip->irq, forte_interrupt, IRQF_SHARED, DRIVER_NAME,
-			 chip)) {
-		printk (KERN_WARNING PFX "Unable to reserve IRQ");
-		ret = -EIO;
-		goto error;
-	}		
-	
-	pci_set_drvdata (pci_dev, chip);
-
-	printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%16llX IRQ %u\n",
-		chip->iobase, (unsigned long long)pci_resource_end (pci_dev, 0),
-		chip->irq);
-
-	/* Power it up */
-	if ((ret = forte_chip_init (chip)) == 0)
-		return 0;
-
- error:
-	if (chip->irq)
-		free_irq (chip->irq, chip);
-
-	if (chip->iobase) 
-		release_region (pci_resource_start (pci_dev, 0),
-				pci_resource_len (pci_dev, 0));
-		
-	kfree (chip);
-
-	return ret;
-}
-
-
-/**
- * forte_remove:
- * @pci_dev:	PCI device to unclaim
- *
- */
-
-static void 
-forte_remove (struct pci_dev *pci_dev)
-{
-	struct forte_chip *chip = pci_get_drvdata (pci_dev);
-
-	if (chip == NULL)
-		return;
-
-	/* Turn volume down to avoid popping */
-	outw (0x1f1f, chip->iobase + FORTE_PCM_VOL);
-	outw (0x1f1f, chip->iobase + FORTE_FM_VOL);
-	outw (0x1f1f, chip->iobase + FORTE_I2S_VOL);
-
-	forte_proc_remove();
-	free_irq (chip->irq, chip);
-	release_region (chip->iobase, pci_resource_len (pci_dev, 0));
-
-	unregister_sound_dsp (chip->dsp);
-	unregister_sound_mixer (chip->ac97->dev_mixer);
-	ac97_release_codec(chip->ac97);
-	kfree (chip);
-
-	printk (KERN_INFO PFX "driver released\n");
-}
-
-
-static struct pci_device_id forte_pci_ids[] = {
-	{ 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
-	{ 0, }
-};
-
-
-static struct pci_driver forte_pci_driver = {
-	.name			= DRIVER_NAME,
-	.id_table		= forte_pci_ids,
-	.probe	 		= forte_probe,
-	.remove			= forte_remove,
-
-};
-
-
-/**
- * forte_init_module:
- *
- */
-
-static int __init
-forte_init_module (void)
-{
-	printk (KERN_INFO PFX DRIVER_VERSION "\n");
-
-	return pci_register_driver (&forte_pci_driver);
-}
-
-
-/**
- * forte_cleanup_module:
- *
- */
-
-static void __exit 
-forte_cleanup_module (void)
-{
-	pci_unregister_driver (&forte_pci_driver);
-}
-
-
-module_init(forte_init_module);
-module_exit(forte_cleanup_module);
-
-MODULE_AUTHOR("Martin K. Petersen <mkp@mkp.net>");
-MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE (pci, forte_pci_ids);
diff --git a/sound/oss/gus.h b/sound/oss/gus.h
deleted file mode 100644
index 3d5271b..0000000
--- a/sound/oss/gus.h
+++ /dev/null
@@ -1,24 +0,0 @@
-
-#include "ad1848.h"
-
-/*	From gus_card.c */
-int gus_set_midi_irq(int num);
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs * dummy);
-
-/*	From gus_wave.c */
-int gus_wave_detect(int baseaddr);
-void gus_wave_init(struct address_info *hw_config);
-void gus_wave_unload (struct address_info *hw_config);
-void gus_voice_irq(void);
-void gus_write8(int reg, unsigned int data);
-void guswave_dma_irq(void);
-void gus_delay(void);
-int gus_default_mixer_ioctl (int dev, unsigned int cmd, void __user *arg);
-void gus_timer_command (unsigned int addr, unsigned int val);
-
-/*	From gus_midi.c */
-void gus_midi_init(struct address_info *hw_config);
-void gus_midi_interrupt(int dummy);
-
-/*	From ics2101.c */
-int ics2101_mixer_init(void);
diff --git a/sound/oss/gus_card.c b/sound/oss/gus_card.c
deleted file mode 100644
index a3d6ae3..0000000
--- a/sound/oss/gus_card.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * sound/oss/gus_card.c
- *
- * Detection routine for the Gravis Ultrasound.
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- *
- * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious
- *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
- * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups.
- *
- * Status:
- *              Tested... 
- */
-      
- 
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_hw.h"
-
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy);
-
-int             gus_base = 0, gus_irq = 0, gus_dma = 0;
-int             gus_no_wave_dma = 0; 
-extern int      gus_wave_volume;
-extern int      gus_pcm_volume;
-extern int      have_gus_max;
-int             gus_pnp_flag = 0;
-#ifdef CONFIG_SOUND_GUS16
-static int      db16;	/* Has a Gus16 AD1848 on it */
-#endif
-
-static void __init attach_gus(struct address_info *hw_config)
-{
-	gus_wave_init(hw_config);
-
-	if (sound_alloc_dma(hw_config->dma, "GUS"))
-		printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma);
-	if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
-		if (sound_alloc_dma(hw_config->dma2, "GUS(2)"))
-			printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2);
-	gus_midi_init(hw_config);
-	if(request_irq(hw_config->irq, gusintr, 0,  "Gravis Ultrasound", hw_config)<0)
-		printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq);
-
-	return;
-}
-
-static int __init probe_gus(struct address_info *hw_config)
-{
-	int             irq;
-	int             io_addr;
-
-	if (hw_config->card_subtype == 1)
-		gus_pnp_flag = 1;
-
-	irq = hw_config->irq;
-
-	if (hw_config->card_subtype == 0)	/* GUS/MAX/ACE */
-		if (irq != 3 && irq != 5 && irq != 7 && irq != 9 &&
-		    irq != 11 && irq != 12 && irq != 15)
-		  {
-			  printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq);
-			  return 0;
-		  }
-	if (gus_wave_detect(hw_config->io_base))
-		return 1;
-
-#ifndef EXCLUDE_GUS_IODETECT
-
-	/*
-	 * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
-	 */
-
-	for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) {
-		if (io_addr == hw_config->io_base)	/* Already tested */
-			continue;
-		if (gus_wave_detect(io_addr)) {
-			hw_config->io_base = io_addr;
-			return 1;
-		}
-	}
-#endif
-
-	printk("NO GUS card found !\n");
-	return 0;
-}
-
-static void __exit unload_gus(struct address_info *hw_config)
-{
-	DDB(printk("unload_gus(%x)\n", hw_config->io_base));
-
-	gus_wave_unload(hw_config);
-
-	release_region(hw_config->io_base, 16);
-	release_region(hw_config->io_base + 0x100, 12);		/* 0x10c-> is MAX */
-	free_irq(hw_config->irq, hw_config);
-
-	sound_free_dma(hw_config->dma);
-
-	if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
-		sound_free_dma(hw_config->dma2);
-}
-
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
-	unsigned char src;
-	extern int gus_timer_enabled;
-	int handled = 0;
-
-#ifdef CONFIG_SOUND_GUSMAX
-	if (have_gus_max) {
-		struct address_info *hw_config = dev_id;
-		adintr(irq, (void *)hw_config->slots[1], NULL);
-	}
-#endif
-#ifdef CONFIG_SOUND_GUS16
-	if (db16) {
-		struct address_info *hw_config = dev_id;
-		adintr(irq, (void *)hw_config->slots[3], NULL);
-	}
-#endif
-
-	while (1)
-	{
-		if (!(src = inb(u_IrqStatus)))
-			break;
-		handled = 1;
-		if (src & DMA_TC_IRQ)
-		{
-			guswave_dma_irq();
-		}
-		if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
-		{
-			gus_midi_interrupt(0);
-		}
-		if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
-		{
-			if (gus_timer_enabled)
-				sound_timer_interrupt();
-			gus_write8(0x45, 0);	/* Ack IRQ */
-			gus_timer_command(4, 0x80);		/* Reset IRQ flags */
-		}
-		if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
-			gus_voice_irq();
-	}
-	return IRQ_RETVAL(handled);
-}
-
-/*
- *	Some extra code for the 16 bit sampling option
- */
-
-#ifdef CONFIG_SOUND_GUS16
-
-static int __init init_gus_db16(struct address_info *hw_config)
-{
-	struct resource *ports;
-
-	ports = request_region(hw_config->io_base, 4, "ad1848");
-	if (!ports)
-		return 0;
-
-	if (!ad1848_detect(ports, NULL, hw_config->osp)) {
-		release_region(hw_config->io_base, 4);
-		return 0;
-	}
-
-	gus_pcm_volume = 100;
-	gus_wave_volume = 90;
-
-	hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", ports,
-					  hw_config->irq,
-					  hw_config->dma,
-					  hw_config->dma, 0,
-					  hw_config->osp,
-					  THIS_MODULE);
-	return 1;
-}
-
-static void __exit unload_gus_db16(struct address_info *hw_config)
-{
-
-	ad1848_unload(hw_config->io_base,
-		      hw_config->irq,
-		      hw_config->dma,
-		      hw_config->dma, 0);
-	sound_unload_audiodev(hw_config->slots[3]);
-}
-#endif
-
-#ifdef CONFIG_SOUND_GUS16
-static int gus16;
-#endif
-#ifdef CONFIG_SOUND_GUSMAX
-static int no_wave_dma;   /* Set if no dma is to be used for the
-                                   wave table (GF1 chip) */
-#endif
-
-
-/*
- *    Note DMA2 of -1 has the right meaning in the GUS driver as well
- *      as here. 
- */
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1;	/* Set this for modules that need it */
-static int __initdata type = 0;		/* 1 for PnP */
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma16, int, 0);
-module_param(type, int, 0);
-#ifdef CONFIG_SOUND_GUSMAX
-module_param(no_wave_dma, int, 0);
-#endif
-#ifdef CONFIG_SOUND_GUS16
-module_param(db16, int, 0);
-module_param(gus16, int, 0);
-#endif
-MODULE_LICENSE("GPL");
-
-static int __init init_gus(void)
-{
-	printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-
-	cfg.io_base = io;
-	cfg.irq = irq;
-	cfg.dma = dma;
-	cfg.dma2 = dma16;
-	cfg.card_subtype = type;
-#ifdef CONFIG_SOUND_GUSMAX
-	gus_no_wave_dma = no_wave_dma;
-#endif
-
-	if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
-		printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n");
-		return -EINVAL;
-	}
-
-#ifdef CONFIG_SOUND_GUS16
-	if (gus16 && init_gus_db16(&cfg))
-		db16 = 1;
-#endif
-	if (!probe_gus(&cfg))
-		return -ENODEV;
-	attach_gus(&cfg);
-
-	return 0;
-}
-
-static void __exit cleanup_gus(void)
-{
-#ifdef CONFIG_SOUND_GUS16
-	if (db16)
-		unload_gus_db16(&cfg);
-#endif
-	unload_gus(&cfg);
-}
-
-module_init(init_gus);
-module_exit(cleanup_gus);
-
-#ifndef MODULE
-static int __init setup_gus(char *str)
-{
-	/* io, irq, dma, dma2 */
-	int ints[5];
-	
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	
-	io	= ints[1];
-	irq	= ints[2];
-	dma	= ints[3];
-	dma16	= ints[4];
-
-	return 1;
-}
-
-__setup("gus=", setup_gus);
-#endif
diff --git a/sound/oss/gus_hw.h b/sound/oss/gus_hw.h
deleted file mode 100644
index f97a0b8..0000000
--- a/sound/oss/gus_hw.h
+++ /dev/null
@@ -1,50 +0,0 @@
-
-/*
- * I/O addresses
- */
-
-#define u_Base			(gus_base + 0x000)
-#define u_Mixer			u_Base
-#define u_Status		(gus_base + 0x006)
-#define u_TimerControl		(gus_base + 0x008)
-#define u_TimerData		(gus_base + 0x009)
-#define u_IRQDMAControl		(gus_base + 0x00b)
-#define u_MidiControl		(gus_base + 0x100)
-#define 	MIDI_RESET		0x03
-#define		MIDI_ENABLE_XMIT	0x20
-#define		MIDI_ENABLE_RCV		0x80
-#define u_MidiStatus		u_MidiControl
-#define		MIDI_RCV_FULL		0x01
-#define 	MIDI_XMIT_EMPTY		0x02
-#define 	MIDI_FRAME_ERR		0x10
-#define 	MIDI_OVERRUN		0x20
-#define 	MIDI_IRQ_PEND		0x80
-#define u_MidiData		(gus_base + 0x101)
-#define u_Voice			(gus_base + 0x102)
-#define u_Command		(gus_base + 0x103)
-#define u_DataLo		(gus_base + 0x104)
-#define u_DataHi		(gus_base + 0x105)
-#define u_MixData               (gus_base + 0x106)   /* Rev. 3.7+ mixing */
-#define u_MixSelect             (gus_base + 0x506)   /* registers.       */
-#define u_IrqStatus		u_Status
-#	define MIDI_TX_IRQ		0x01	/* pending MIDI xmit IRQ */
-#	define MIDI_RX_IRQ		0x02	/* pending MIDI recv IRQ */
-#	define GF1_TIMER1_IRQ		0x04	/* general purpose timer */
-#	define GF1_TIMER2_IRQ		0x08	/* general purpose timer */
-#	define WAVETABLE_IRQ		0x20	/* pending wavetable IRQ */
-#	define ENVELOPE_IRQ		0x40	/* pending volume envelope IRQ */
-#	define DMA_TC_IRQ		0x80	/* pending dma tc IRQ */
-
-#define ICS2101		1
-#	define ICS_MIXDEVS	6
-#	define DEV_MIC		0
-#	define DEV_LINE		1
-#	define DEV_CD		2
-#	define DEV_GF1		3
-#	define DEV_UNUSED	4
-#	define DEV_VOL		5
-
-#	define CHN_LEFT		0
-#	define CHN_RIGHT	1
-#define CS4231		2
-#define u_DRAMIO		(gus_base + 0x107)
diff --git a/sound/oss/gus_linearvol.h b/sound/oss/gus_linearvol.h
deleted file mode 100644
index 7ad0c30..0000000
--- a/sound/oss/gus_linearvol.h
+++ /dev/null
@@ -1,18 +0,0 @@
-static unsigned short gus_linearvol[128] = {
- 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
- 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
- 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
- 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
- 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
- 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
- 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
- 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
- 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
- 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
- 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
- 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
- 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
- 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
- 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
- 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
-};
diff --git a/sound/oss/gus_midi.c b/sound/oss/gus_midi.c
deleted file mode 100644
index d1997a4..0000000
--- a/sound/oss/gus_midi.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * sound/oss/gus_midi.c
- *
- * The low level driver for the GUS Midi Interface.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- *		Added __init to gus_midi_init()
- */
-
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_hw.h"
-
-static int      midi_busy, input_opened;
-static int      my_dev;
-static int      output_used;
-static volatile unsigned char gus_midi_control;
-static void     (*midi_input_intr) (int dev, unsigned char data);
-
-static unsigned char tmp_queue[256];
-extern int      gus_pnp_flag;
-static volatile int qlen;
-static volatile unsigned char qhead, qtail;
-extern int      gus_base, gus_irq, gus_dma;
-extern int     *gus_osp;
-extern spinlock_t gus_lock;
-
-static int GUS_MIDI_STATUS(void)
-{
-	return inb(u_MidiStatus);
-}
-
-static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev))
-{
-	if (midi_busy)
-	{
-/*		printk("GUS: Midi busy\n");*/
-		return -EBUSY;
-	}
-	outb((MIDI_RESET), u_MidiControl);
-	gus_delay();
-
-	gus_midi_control = 0;
-	input_opened = 0;
-
-	if (mode == OPEN_READ || mode == OPEN_READWRITE)
-		if (!gus_pnp_flag)
-		{
-			gus_midi_control |= MIDI_ENABLE_RCV;
-			input_opened = 1;
-		}
-	outb((gus_midi_control), u_MidiControl);	/* Enable */
-
-	midi_busy = 1;
-	qlen = qhead = qtail = output_used = 0;
-	midi_input_intr = input;
-
-	return 0;
-}
-
-static int dump_to_midi(unsigned char midi_byte)
-{
-	unsigned long   flags;
-	int             ok = 0;
-
-	output_used = 1;
-
-	spin_lock_irqsave(&gus_lock, flags);
-
-	if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY)
-	{
-		ok = 1;
-		outb((midi_byte), u_MidiData);
-	}
-	else
-	{
-		/*
-		 * Enable Midi xmit interrupts (again)
-		 */
-		gus_midi_control |= MIDI_ENABLE_XMIT;
-		outb((gus_midi_control), u_MidiControl);
-	}
-
-	spin_unlock_irqrestore(&gus_lock,flags);
-	return ok;
-}
-
-static void gus_midi_close(int dev)
-{
-	/*
-	 * Reset FIFO pointers, disable intrs
-	 */
-
-	outb((MIDI_RESET), u_MidiControl);
-	midi_busy = 0;
-}
-
-static int gus_midi_out(int dev, unsigned char midi_byte)
-{
-	unsigned long   flags;
-
-	/*
-	 * Drain the local queue first
-	 */
-	spin_lock_irqsave(&gus_lock, flags);
-
-	while (qlen && dump_to_midi(tmp_queue[qhead]))
-	{
-		qlen--;
-		qhead++;
-	}
-	spin_unlock_irqrestore(&gus_lock,flags);
-
-	/*
-	 *	Output the byte if the local queue is empty.
-	 */
-
-	if (!qlen)
-		if (dump_to_midi(midi_byte))
-			return 1;	/*
-					 * OK
-					 */
-
-	/*
-	 *	Put to the local queue
-	 */
-
-	if (qlen >= 256)
-		return 0;	/*
-				 * Local queue full
-				 */
-	spin_lock_irqsave(&gus_lock, flags);
-
-	tmp_queue[qtail] = midi_byte;
-	qlen++;
-	qtail++;
-
-	spin_unlock_irqrestore(&gus_lock,flags);
-	return 1;
-}
-
-static int gus_midi_start_read(int dev)
-{
-	return 0;
-}
-
-static int gus_midi_end_read(int dev)
-{
-	return 0;
-}
-
-static void gus_midi_kick(int dev)
-{
-}
-
-static int gus_midi_buffer_status(int dev)
-{
-	unsigned long   flags;
-
-	if (!output_used)
-		return 0;
-
-	spin_lock_irqsave(&gus_lock, flags);
-
-	if (qlen && dump_to_midi(tmp_queue[qhead]))
-	{
-		qlen--;
-		qhead++;
-	}
-	spin_unlock_irqrestore(&gus_lock,flags);
-	return (qlen > 0) || !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
-}
-
-#define MIDI_SYNTH_NAME	"Gravis Ultrasound Midi"
-#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-static struct midi_operations gus_midi_operations =
-{
-	.owner		= THIS_MODULE,
-	.info		= {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
-	.converter	= &std_midi_synth,
-	.in_info	= {0},
-	.open		= gus_midi_open,
-	.close		= gus_midi_close,
-	.outputc	= gus_midi_out,
-	.start_read	= gus_midi_start_read,
-	.end_read	= gus_midi_end_read,
-	.kick		= gus_midi_kick,
-	.buffer_status	= gus_midi_buffer_status,
-};
-
-void __init gus_midi_init(struct address_info *hw_config)
-{
-	int dev = sound_alloc_mididev();
-
-	if (dev == -1)
-	{
-		printk(KERN_INFO "gus_midi: Too many midi devices detected\n");
-		return;
-	}
-	outb((MIDI_RESET), u_MidiControl);
-
-	std_midi_synth.midi_dev = my_dev = dev;
-	hw_config->slots[2] = dev;
-	midi_devs[dev] = &gus_midi_operations;
-	sequencer_init();
-	return;
-}
-
-void gus_midi_interrupt(int dummy)
-{
-	volatile unsigned char stat, data;
-	int timeout = 10;
-
-	spin_lock(&gus_lock);
-
-	while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY))
-	{
-		if (stat & MIDI_RCV_FULL)
-		{
-			data = inb(u_MidiData);
-			if (input_opened)
-				midi_input_intr(my_dev, data);
-		}
-		if (stat & MIDI_XMIT_EMPTY)
-		{
-			while (qlen && dump_to_midi(tmp_queue[qhead]))
-			{
-				qlen--;
-				qhead++;
-			}
-			if (!qlen)
-			{
-			      /*
-			       * Disable Midi output interrupts, since no data in the buffer
-			       */
-			      gus_midi_control &= ~MIDI_ENABLE_XMIT;
-			      outb((gus_midi_control), u_MidiControl);
-			      outb((gus_midi_control), u_MidiControl);
-			}
-		}
-	}
-	spin_unlock(&gus_lock);
-}
diff --git a/sound/oss/gus_vol.c b/sound/oss/gus_vol.c
deleted file mode 100644
index 6ae6924..0000000
--- a/sound/oss/gus_vol.c
+++ /dev/null
@@ -1,153 +0,0 @@
-
-/*
- * gus_vol.c - Compute volume for GUS.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_linearvol.h"
-
-#define GUS_VOLUME	gus_wave_volume
-
-
-extern int      gus_wave_volume;
-
-/*
- * Calculate gus volume from note velocity, main volume, expression, and
- * intrinsic patch volume given in patch library.  Expression is multiplied
- * in, so it emphasizes differences in note velocity, while main volume is
- * added in -- I don't know whether this is right, but it seems reasonable to
- * me.  (In the previous stage, main volume controller messages were changed
- * to expression controller messages, if they were found to be used for
- * dynamic volume adjustments, so here, main volume can be assumed to be
- * constant throughout a song.)
- *
- * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
- * we can give a big boost to very weak voices like nylon guitar and the
- * basses.  The normal value is 64.  Strings are assigned lower values.
- */
-
-unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev)
-{
-	int i, m, n, x;
-
-
-	/*
-	 * A voice volume of 64 is considered neutral, so adjust the main volume if
-	 * something other than this neutral value was assigned in the patch
-	 * library.
-	 */
-	x = 256 + 6 * (voicev - 64);
-
-	/*
-	 * Boost expression by voice volume above neutral.
-	 */
-	 
-	if (voicev > 65)
-		xpn += voicev - 64;
-	xpn += (voicev - 64) / 2;
-
-	/*
-	 * Combine multiplicative and level components.
-	 */
-	x = vel * xpn * 6 + (voicev / 4) * x;
-
-#ifdef GUS_VOLUME
-	/*
-	 * Further adjustment by installation-specific master volume control
-	 * (default 60).
-	 */
-	x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
-#endif
-
-#ifdef GUS_USE_CHN_MAIN_VOLUME
-	/*
-	 * Experimental support for the channel main volume
-	 */
-
-	mainv = (mainv / 2) + 64;	/* Scale to 64 to 127 */
-	x = (x * mainv * mainv) / 16384;
-#endif
-
-	if (x < 2)
-		return (0);
-	else if (x >= 65535)
-		return ((15 << 8) | 255);
-
-	/*
-	 * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit
-	 * mantissa m.
-	 */
-	 
-	n = x;
-	i = 7;
-	if (n < 128)
-	{
-		  while (i > 0 && n < (1 << i))
-			  i--;
-	}
-	else
-	{
-		while (n > 255)
-		{
-			  n >>= 1;
-			  i++;
-		}
-	}
-	/*
-	 * Mantissa is part of linear volume not expressed in exponent.  (This is
-	 * not quite like real logs -- I wonder if it's right.)
-	 */
-	m = x - (1 << i);
-
-	/*
-	 * Adjust mantissa to 8 bits.
-	 */
-	if (m > 0)
-	{
-		if (i > 8)
-			m >>= i - 8;
-		else if (i < 8)
-			m <<= 8 - i;
-	}
-	return ((i << 8) + m);
-}
-
-/*
- * Volume-values are interpreted as linear values. Volume is based on the
- * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
- * and the volume set by the mixer-device (default 60%).
- */
-
-unsigned short gus_linear_vol(int vol, int mainvol)
-{
-	int mixer_mainvol;
-
-	if (vol <= 0)
-		vol = 0;
-	else if (vol >= 127)
-		vol = 127;
-
-#ifdef GUS_VOLUME
-	mixer_mainvol = GUS_VOLUME;
-#else
-	mixer_mainvol = 100;
-#endif
-
-#ifdef GUS_USE_CHN_MAIN_VOLUME
-	if (mainvol <= 0)
-		mainvol = 0;
-	else if (mainvol >= 127)
-		mainvol = 127;
-#else
-	mainvol = 127;
-#endif
-	return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
-}
diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c
deleted file mode 100644
index 597db7a..0000000
--- a/sound/oss/gus_wave.c
+++ /dev/null
@@ -1,3464 +0,0 @@
-/*
- * sound/oss/gus_wave.c
- *
- * Driver for the Gravis UltraSound wave table synth.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *
- * Thomas Sailer    : ioctl code reworked (vmalloc/vfree removed)
- * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
- *                    usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
- * Bartlomiej Zolnierkiewicz : added some __init/__exit
- */
- 
-#include <linux/init.h> 
-#include <linux/config.h>
-#include <linux/spinlock.h>
-
-#define GUSPNP_AUTODETECT
-
-#include "sound_config.h"
-#include <linux/ultrasound.h>
-
-#include "gus.h"
-#include "gus_hw.h"
-
-#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
-
-#define MAX_SAMPLE	150
-#define MAX_PATCH	256
-
-#define NOT_SAMPLE	0xffff
-
-struct voice_info
-{
-	unsigned long   orig_freq;
-	unsigned long   current_freq;
-	unsigned long   mode;
-	int             fixed_pitch;
-	int             bender;
-	int             bender_range;
-	int             panning;
-	int             midi_volume;
-	unsigned int    initial_volume;
-	unsigned int    current_volume;
-	int             loop_irq_mode, loop_irq_parm;
-#define LMODE_FINISH		1
-#define LMODE_PCM		2
-#define LMODE_PCM_STOP		3
-	int             volume_irq_mode, volume_irq_parm;
-#define VMODE_HALT		1
-#define VMODE_ENVELOPE		2
-#define VMODE_START_NOTE	3
-
-	int             env_phase;
-	unsigned char   env_rate[6];
-	unsigned char   env_offset[6];
-
-	/*
-	 * Volume computation parameters for gus_adagio_vol()
-	 */
-	int		main_vol, expression_vol, patch_vol;
-
-	/* Variables for "Ultraclick" removal */
-	int             dev_pending, note_pending, volume_pending,
-	                sample_pending;
-	char            kill_pending;
-	long            offset_pending;
-
-};
-
-static struct voice_alloc_info *voice_alloc;
-static struct address_info *gus_hw_config;
-extern int      gus_base;
-extern int      gus_irq, gus_dma;
-extern int      gus_pnp_flag;
-extern int      gus_no_wave_dma;
-static int      gus_dma2 = -1;
-static int      dual_dma_mode;
-static long     gus_mem_size;
-static long     free_mem_ptr;
-static int      gus_busy;
-static int      gus_no_dma;
-static int      nr_voices;
-static int      gus_devnum;
-static int      volume_base, volume_scale, volume_method;
-static int      gus_recmask = SOUND_MASK_MIC;
-static int      recording_active;
-static int      only_read_access;
-static int      only_8_bits;
-
-static int      iw_mode = 0;
-int             gus_wave_volume = 60;
-int             gus_pcm_volume = 80;
-int             have_gus_max = 0;
-static int      gus_line_vol = 100, gus_mic_vol;
-static unsigned char mix_image = 0x00;
-
-int             gus_timer_enabled = 0;
-
-/*
- * Current version of this driver doesn't allow synth and PCM functions
- * at the same time. The active_device specifies the active driver
- */
-
-static int      active_device;
-
-#define GUS_DEV_WAVE		1	/* Wave table synth */
-#define GUS_DEV_PCM_DONE	2	/* PCM device, transfer done */
-#define GUS_DEV_PCM_CONTINUE	3	/* PCM device, transfer done ch. 1/2 */
-
-static int      gus_audio_speed;
-static int      gus_audio_channels;
-static int      gus_audio_bits;
-static int      gus_audio_bsize;
-static char     bounce_buf[8 * 1024];	/* Must match value set to max_fragment */
-
-static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper);
-
-/*
- * Variables and buffers for PCM output
- */
-
-#define MAX_PCM_BUFFERS		(128*MAX_REALTIME_FACTOR)	/* Don't change */
-
-static int      pcm_bsize, pcm_nblk, pcm_banksize;
-static int      pcm_datasize[MAX_PCM_BUFFERS];
-static volatile int pcm_head, pcm_tail, pcm_qlen;
-static volatile int pcm_active;
-static volatile int dma_active;
-static int      pcm_opened;
-static int      pcm_current_dev;
-static int      pcm_current_block;
-static unsigned long pcm_current_buf;
-static int      pcm_current_count;
-static int      pcm_current_intrflag;
-DEFINE_SPINLOCK(gus_lock);
-
-extern int     *gus_osp;
-
-static struct voice_info voices[32];
-
-static int      freq_div_table[] =
-{
-	44100,			/* 14 */
-	41160,			/* 15 */
-	38587,			/* 16 */
-	36317,			/* 17 */
-	34300,			/* 18 */
-	32494,			/* 19 */
-	30870,			/* 20 */
-	29400,			/* 21 */
-	28063,			/* 22 */
-	26843,			/* 23 */
-	25725,			/* 24 */
-	24696,			/* 25 */
-	23746,			/* 26 */
-	22866,			/* 27 */
-	22050,			/* 28 */
-	21289,			/* 29 */
-	20580,			/* 30 */
-	19916,			/* 31 */
-	19293			/* 32 */
-};
-
-static struct patch_info *samples;
-static long     sample_ptrs[MAX_SAMPLE + 1];
-static int      sample_map[32];
-static int      free_sample;
-static int      mixer_type;
-
-
-static int      patch_table[MAX_PATCH];
-static int      patch_map[32];
-
-static struct synth_info gus_info = {
-	"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 
-	0, 16, 0, MAX_PATCH
-};
-
-static void     gus_poke(long addr, unsigned char data);
-static void     compute_and_set_volume(int voice, int volume, int ramp_time);
-extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
-extern unsigned short gus_linear_vol(int vol, int mainvol);
-static void     compute_volume(int voice, int volume);
-static void     do_volume_irq(int voice);
-static void     set_input_volumes(void);
-static void     gus_tmr_install(int io_base);
-
-#define	INSTANT_RAMP		-1	/* Instant change. No ramping */
-#define FAST_RAMP		0	/* Fastest possible ramp */
-
-static void reset_sample_memory(void)
-{
-	int i;
-
-	for (i = 0; i <= MAX_SAMPLE; i++)
-		sample_ptrs[i] = -1;
-	for (i = 0; i < 32; i++)
-		sample_map[i] = -1;
-	for (i = 0; i < 32; i++)
-		patch_map[i] = -1;
-
-	gus_poke(0, 0);		/* Put a silent sample to the beginning */
-	gus_poke(1, 0);
-	free_mem_ptr = 2;
-
-	free_sample = 0;
-
-	for (i = 0; i < MAX_PATCH; i++)
-		patch_table[i] = NOT_SAMPLE;
-}
-
-void gus_delay(void)
-{
-	int i;
-
-	for (i = 0; i < 7; i++)
-		inb(u_DRAMIO);
-}
-
-static void gus_poke(long addr, unsigned char data)
-{				/* Writes a byte to the DRAM */
-	outb((0x43), u_Command);
-	outb((addr & 0xff), u_DataLo);
-	outb(((addr >> 8) & 0xff), u_DataHi);
-
-	outb((0x44), u_Command);
-	outb(((addr >> 16) & 0xff), u_DataHi);
-	outb((data), u_DRAMIO);
-}
-
-static unsigned char gus_peek(long addr)
-{				/* Reads a byte from the DRAM */
-	unsigned char   tmp;
-
-	outb((0x43), u_Command);
-	outb((addr & 0xff), u_DataLo);
-	outb(((addr >> 8) & 0xff), u_DataHi);
-
-	outb((0x44), u_Command);
-	outb(((addr >> 16) & 0xff), u_DataHi);
-	tmp = inb(u_DRAMIO);
-
-	return tmp;
-}
-
-void gus_write8(int reg, unsigned int data)
-{				/* Writes to an indirect register (8 bit) */
-	outb((reg), u_Command);
-	outb(((unsigned char) (data & 0xff)), u_DataHi);
-}
-
-static unsigned char gus_read8(int reg)
-{				
-	/* Reads from an indirect register (8 bit). Offset 0x80. */
-	unsigned char   val;
-
-	outb((reg | 0x80), u_Command);
-	val = inb(u_DataHi);
-
-	return val;
-}
-
-static unsigned char gus_look8(int reg)
-{
-	/* Reads from an indirect register (8 bit). No additional offset. */
-	unsigned char   val;
-
-	outb((reg), u_Command);
-	val = inb(u_DataHi);
-
-	return val;
-}
-
-static void gus_write16(int reg, unsigned int data)
-{
-	/* Writes to an indirect register (16 bit) */
-	outb((reg), u_Command);
-
-	outb(((unsigned char) (data & 0xff)), u_DataLo);
-	outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi);
-}
-
-static unsigned short gus_read16(int reg)
-{
-	/* Reads from an indirect register (16 bit). Offset 0x80. */
-	unsigned char   hi, lo;
-
-	outb((reg | 0x80), u_Command);
-
-	lo = inb(u_DataLo);
-	hi = inb(u_DataHi);
-
-	return ((hi << 8) & 0xff00) | lo;
-}
-
-static unsigned short gus_look16(int reg)
-{		
-	/* Reads from an indirect register (16 bit). No additional offset. */
-	unsigned char   hi, lo;
-
-	outb((reg), u_Command);
-
-	lo = inb(u_DataLo);
-	hi = inb(u_DataHi);
-
-	return ((hi << 8) & 0xff00) | lo;
-}
-
-static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit)
-{
-	/* Writes an 24 bit memory address */
-	unsigned long   hold_address;
-
-	if (is16bit)
-	{
-		if (iw_mode)
-		{
-			/* Interwave spesific address translations */
-			address >>= 1;
-		}
-		else
-		{
-			/*
-			 * Special processing required for 16 bit patches
-			 */
-
-			hold_address = address;
-			address = address >> 1;
-			address &= 0x0001ffffL;
-			address |= (hold_address & 0x000c0000L);
-		}
-	}
-	gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
-	gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
-		    + (frac << 5));
-	/* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */
-	gus_delay();
-	gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
-	gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
-		    + (frac << 5));
-}
-
-static void gus_select_voice(int voice)
-{
-	if (voice < 0 || voice > 31)
-		return;
-	outb((voice), u_Voice);
-}
-
-static void gus_select_max_voices(int nvoices)
-{
-	if (iw_mode)
-		nvoices = 32;
-	if (nvoices < 14)
-		nvoices = 14;
-	if (nvoices > 32)
-		nvoices = 32;
-
-	voice_alloc->max_voice = nr_voices = nvoices;
-	gus_write8(0x0e, (nvoices - 1) | 0xc0);
-}
-
-static void gus_voice_on(unsigned int mode)
-{
-	gus_write8(0x00, (unsigned char) (mode & 0xfc));
-	gus_delay();
-	gus_write8(0x00, (unsigned char) (mode & 0xfc));
-}
-
-static void gus_voice_off(void)
-{
-	gus_write8(0x00, gus_read8(0x00) | 0x03);
-}
-
-static void gus_voice_mode(unsigned int m)
-{
-	unsigned char   mode = (unsigned char) (m & 0xff);
-
-	gus_write8(0x00, (gus_read8(0x00) & 0x03) |
-		   (mode & 0xfc));	/* Don't touch last two bits */
-	gus_delay();
-	gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc));
-}
-
-static void gus_voice_freq(unsigned long freq)
-{
-	unsigned long   divisor = freq_div_table[nr_voices - 14];
-	unsigned short  fc;
-
-	/* Interwave plays at 44100 Hz with any number of voices */
-	if (iw_mode)
-		fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100);
-	else
-		fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
-	fc = fc << 1;
-
-	gus_write16(0x01, fc);
-}
-
-static void gus_voice_volume(unsigned int vol)
-{
-	gus_write8(0x0d, 0x03);	/* Stop ramp before setting volume */
-	gus_write16(0x09, (unsigned short) (vol << 4));
-}
-
-static void gus_voice_balance(unsigned int balance)
-{
-	gus_write8(0x0c, (unsigned char) (balance & 0xff));
-}
-
-static void gus_ramp_range(unsigned int low, unsigned int high)
-{
-	gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff));
-	gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff));
-}
-
-static void gus_ramp_rate(unsigned int scale, unsigned int rate)
-{
-	gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
-}
-
-static void gus_rampon(unsigned int m)
-{
-	unsigned char   mode = (unsigned char) (m & 0xff);
-
-	gus_write8(0x0d, mode & 0xfc);
-	gus_delay();
-	gus_write8(0x0d, mode & 0xfc);
-}
-
-static void gus_ramp_mode(unsigned int m)
-{
-	unsigned char mode = (unsigned char) (m & 0xff);
-
-	gus_write8(0x0d, (gus_read8(0x0d) & 0x03) |
-		   (mode & 0xfc));	/* Leave the last 2 bits alone */
-	gus_delay();
-	gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc));
-}
-
-static void gus_rampoff(void)
-{
-	gus_write8(0x0d, 0x03);
-}
-
-static void gus_set_voice_pos(int voice, long position)
-{
-	int sample_no;
-
-	if ((sample_no = sample_map[voice]) != -1) {
-		if (position < samples[sample_no].len) {
-			if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
-				voices[voice].offset_pending = position;
-			else
-				gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0,
-				 samples[sample_no].mode & WAVE_16_BITS);
-		}
-	}
-}
-
-static void gus_voice_init(int voice)
-{
-	unsigned long   flags;
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-	gus_voice_volume(0);
-	gus_voice_off();
-	gus_write_addr(0x0a, 0, 0, 0);	/* Set current position to 0 */
-	gus_write8(0x00, 0x03);	/* Voice off */
-	gus_write8(0x0d, 0x03);	/* Ramping off */
-	voice_alloc->map[voice] = 0;
-	voice_alloc->alloc_times[voice] = 0;
-	spin_unlock_irqrestore(&gus_lock,flags);
-
-}
-
-static void gus_voice_init2(int voice)
-{
-	voices[voice].panning = 0;
-	voices[voice].mode = 0;
-	voices[voice].orig_freq = 20000;
-	voices[voice].current_freq = 20000;
-	voices[voice].bender = 0;
-	voices[voice].bender_range = 200;
-	voices[voice].initial_volume = 0;
-	voices[voice].current_volume = 0;
-	voices[voice].loop_irq_mode = 0;
-	voices[voice].loop_irq_parm = 0;
-	voices[voice].volume_irq_mode = 0;
-	voices[voice].volume_irq_parm = 0;
-	voices[voice].env_phase = 0;
-	voices[voice].main_vol = 127;
-	voices[voice].patch_vol = 127;
-	voices[voice].expression_vol = 127;
-	voices[voice].sample_pending = -1;
-	voices[voice].fixed_pitch = 0;
-}
-
-static void step_envelope(int voice)
-{
-	unsigned        vol, prev_vol, phase;
-	unsigned char   rate;
-	unsigned long flags;
-
-	if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
-	{
-		spin_lock_irqsave(&gus_lock,flags);
-		gus_select_voice(voice);
-		gus_rampoff();
-		spin_unlock_irqrestore(&gus_lock,flags);
-		return;
-		/*
-		 * Sustain phase begins. Continue envelope after receiving note off.
-		 */
-	}
-	if (voices[voice].env_phase >= 5)
-	{
-		/* Envelope finished. Shoot the voice down */
-		gus_voice_init(voice);
-		return;
-	}
-	prev_vol = voices[voice].current_volume;
-	phase = ++voices[voice].env_phase;
-	compute_volume(voice, voices[voice].midi_volume);
-	vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
-	rate = voices[voice].env_rate[phase];
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-
-	gus_voice_volume(prev_vol);
-
-
-	gus_write8(0x06, rate);	/* Ramping rate */
-
-	voices[voice].volume_irq_mode = VMODE_ENVELOPE;
-
-	if (((vol - prev_vol) / 64) == 0)	/* No significant volume change */
-	{
-		spin_unlock_irqrestore(&gus_lock,flags);
-		step_envelope(voice);		/* Continue the envelope on the next step */
-		return;
-	}
-	if (vol > prev_vol)
-	{
-		if (vol >= (4096 - 64))
-			vol = 4096 - 65;
-		gus_ramp_range(0, vol);
-		gus_rampon(0x20);	/* Increasing volume, with IRQ */
-	}
-	else
-	{
-		if (vol <= 64)
-			vol = 65;
-		gus_ramp_range(vol, 4030);
-		gus_rampon(0x60);	/* Decreasing volume, with IRQ */
-	}
-	voices[voice].current_volume = vol;
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void init_envelope(int voice)
-{
-	voices[voice].env_phase = -1;
-	voices[voice].current_volume = 64;
-
-	step_envelope(voice);
-}
-
-static void start_release(int voice)
-{
-	if (gus_read8(0x00) & 0x03)
-		return;		/* Voice already stopped */
-
-	voices[voice].env_phase = 2;	/* Will be incremented by step_envelope */
-
-	voices[voice].current_volume = voices[voice].initial_volume =
-						gus_read16(0x09) >> 4;	/* Get current volume */
-
-	voices[voice].mode &= ~WAVE_SUSTAIN_ON;
-	gus_rampoff();
-	step_envelope(voice);
-}
-
-static void gus_voice_fade(int voice)
-{
-	int instr_no = sample_map[voice], is16bits;
-	unsigned long flags;
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-
-	if (instr_no < 0 || instr_no > MAX_SAMPLE)
-	{
-		gus_write8(0x00, 0x03);	/* Hard stop */
-		voice_alloc->map[voice] = 0;
-		spin_unlock_irqrestore(&gus_lock,flags);
-		return;
-	}
-	is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0;	/* 8 or 16 bits */
-
-	if (voices[voice].mode & WAVE_ENVELOPES)
-	{
-		start_release(voice);
-		spin_unlock_irqrestore(&gus_lock,flags);
-		return;
-	}
-	/*
-	 * Ramp the volume down but not too quickly.
-	 */
-	if ((int) (gus_read16(0x09) >> 4) < 100)	/* Get current volume */
-	{
-		gus_voice_off();
-		gus_rampoff();
-		gus_voice_init(voice);
-		spin_unlock_irqrestore(&gus_lock,flags);
-		return;
-	}
-	gus_ramp_range(65, 4030);
-	gus_ramp_rate(2, 4);
-	gus_rampon(0x40 | 0x20);	/* Down, once, with IRQ */
-	voices[voice].volume_irq_mode = VMODE_HALT;
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void gus_reset(void)
-{
-	int i;
-
-	gus_select_max_voices(24);
-	volume_base = 3071;
-	volume_scale = 4;
-	volume_method = VOL_METHOD_ADAGIO;
-
-	for (i = 0; i < 32; i++)
-	{
-		gus_voice_init(i);	/* Turn voice off */
-		gus_voice_init2(i);
-	}
-}
-
-static void gus_initialize(void)
-{
-	unsigned long flags;
-	unsigned char dma_image, irq_image, tmp;
-
-	static unsigned char gus_irq_map[16] = 	{
-		0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7
-	};
-
-	static unsigned char gus_dma_map[8] = {
-		0, 1, 0, 2, 0, 3, 4, 5
-	};
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_write8(0x4c, 0);	/* Reset GF1 */
-	gus_delay();
-	gus_delay();
-
-	gus_write8(0x4c, 1);	/* Release Reset */
-	gus_delay();
-	gus_delay();
-
-	/*
-	 * Clear all interrupts
-	 */
-
-	gus_write8(0x41, 0);	/* DMA control */
-	gus_write8(0x45, 0);	/* Timer control */
-	gus_write8(0x49, 0);	/* Sample control */
-
-	gus_select_max_voices(24);
-
-	inb(u_Status);		/* Touch the status register */
-
-	gus_look8(0x41);	/* Clear any pending DMA IRQs */
-	gus_look8(0x49);	/* Clear any pending sample IRQs */
-	gus_read8(0x0f);	/* Clear pending IRQs */
-
-	gus_reset();		/* Resets all voices */
-
-	gus_look8(0x41);	/* Clear any pending DMA IRQs */
-	gus_look8(0x49);	/* Clear any pending sample IRQs */
-	gus_read8(0x0f);	/* Clear pending IRQs */
-
-	gus_write8(0x4c, 7);	/* Master reset | DAC enable | IRQ enable */
-
-	/*
-	 * Set up for Digital ASIC
-	 */
-
-	outb((0x05), gus_base + 0x0f);
-
-	mix_image |= 0x02;	/* Disable line out (for a moment) */
-	outb((mix_image), u_Mixer);
-
-	outb((0x00), u_IRQDMAControl);
-
-	outb((0x00), gus_base + 0x0f);
-
-	/*
-	 * Now set up the DMA and IRQ interface
-	 *
-	 * The GUS supports two IRQs and two DMAs.
-	 *
-	 * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
-	 * Adding this support requires significant changes to the dmabuf.c, dsp.c
-	 * and audio.c also.
-	 */
-
-	irq_image = 0;
-	tmp = gus_irq_map[gus_irq];
-	if (!gus_pnp_flag && !tmp)
-		printk(KERN_WARNING "Warning! GUS IRQ not selected\n");
-	irq_image |= tmp;
-	irq_image |= 0x40;	/* Combine IRQ1 (GF1) and IRQ2 (Midi) */
-
-	dual_dma_mode = 1;
-	if (gus_dma2 == gus_dma || gus_dma2 == -1)
-	{
-		dual_dma_mode = 0;
-		dma_image = 0x40;	/* Combine DMA1 (DRAM) and IRQ2 (ADC) */
-
-		tmp = gus_dma_map[gus_dma];
-		if (!tmp)
-			printk(KERN_WARNING "Warning! GUS DMA not selected\n");
-
-		dma_image |= tmp;
-	}
-	else
-	{
-		/* Setup dual DMA channel mode for GUS MAX */
-
-		dma_image = gus_dma_map[gus_dma];
-		if (!dma_image)
-			printk(KERN_WARNING "Warning! GUS DMA not selected\n");
-
-		tmp = gus_dma_map[gus_dma2] << 3;
-		if (!tmp)
-		{
-			printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n");
-			tmp = 0x40;		/* Combine DMA channels */
-			    dual_dma_mode = 0;
-		}
-		dma_image |= tmp;
-	}
-
-	/*
-	 * For some reason the IRQ and DMA addresses must be written twice
-	 */
-
-	/*
-	 * Doing it first time
-	 */
-
-	outb((mix_image), u_Mixer);	/* Select DMA control */
-	outb((dma_image | 0x80), u_IRQDMAControl);	/* Set DMA address */
-
-	outb((mix_image | 0x40), u_Mixer);	/* Select IRQ control */
-	outb((irq_image), u_IRQDMAControl);	/* Set IRQ address */
-
-	/*
-	 * Doing it second time
-	 */
-
-	outb((mix_image), u_Mixer);	/* Select DMA control */
-	outb((dma_image), u_IRQDMAControl);	/* Set DMA address */
-
-	outb((mix_image | 0x40), u_Mixer);	/* Select IRQ control */
-	outb((irq_image), u_IRQDMAControl);	/* Set IRQ address */
-
-	gus_select_voice(0);	/* This disables writes to IRQ/DMA reg */
-
-	mix_image &= ~0x02;	/* Enable line out */
-	mix_image |= 0x08;	/* Enable IRQ */
-	outb((mix_image), u_Mixer);	/*
-					 * Turn mixer channels on
-					 * Note! Mic in is left off.
-					 */
-
-	gus_select_voice(0);	/* This disables writes to IRQ/DMA reg */
-
-	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
-
-	inb(u_Status);		/* Touch the status register */
-
-	gus_look8(0x41);	/* Clear any pending DMA IRQs */
-	gus_look8(0x49);	/* Clear any pending sample IRQs */
-
-	gus_read8(0x0f);	/* Clear pending IRQs */
-
-	if (iw_mode)
-		gus_write8(0x19, gus_read8(0x19) | 0x01);
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-
-static void __init pnp_mem_init(void)
-{
-#include "iwmem.h"
-#define CHUNK_SIZE (256*1024)
-#define BANK_SIZE (4*1024*1024)
-#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE)
-
-	int bank, chunk, addr, total = 0;
-	int bank_sizes[4];
-	int i, j, bits = -1, testbits = -1, nbanks = 0;
-
-	/*
-	 * This routine determines what kind of RAM is installed in each of the four
-	 * SIMM banks and configures the DRAM address decode logic accordingly.
-	 */
-
-	/*
-	 *    Place the chip into enhanced mode
-	 */
-	gus_write8(0x19, gus_read8(0x19) | 0x01);
-	gus_write8(0x53, gus_look8(0x53) & ~0x02);	/* Select DRAM I/O access */
-
-	/*
-	 * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
-	 */
-
-	gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c);
-
-	/*
-	 * Perform the DRAM size detection for each bank individually.
-	 */
-	for (bank = 0; bank < 4; bank++)
-	{
-		int size = 0;
-
-		addr = bank * BANK_SIZE;
-
-		/* Clean check points of each chunk */
-		for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
-		{
-			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
-			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
-		}
-
-		/* Write a value to each chunk point and verify the result */
-		for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
-		{
-			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55);
-			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA);
-
-			if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 &&
-				gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA)
-			{
-				/* OK. There is RAM. Now check for possible shadows */
-				int ok = 1, chunk2;
-
-				for (chunk2 = 0; ok && chunk2 < chunk; chunk2++)
-					if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) ||
-							gus_peek(addr + chunk2 * CHUNK_SIZE + 1L))
-						ok = 0;	/* Addressing wraps */
-
-				if (ok)
-					size = (chunk + 1) * CHUNK_SIZE;
-			}
-			gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
-			gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
-		}
-		bank_sizes[bank] = size;
-		if (size)
-			nbanks = bank + 1;
-		DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024));
-	}
-
-	if (nbanks == 0)	/* No RAM - Give up */
-	{
-		printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n");
-		printk(KERN_ERR "Sound: Unable to work with this card.\n");
-		gus_write8(0x19, gus_read8(0x19) & ~0x01);
-		gus_mem_size = 0;
-		return;
-	}
-
-	/*
-	 * Now we know how much DRAM there is in each bank. The next step is
-	 * to find a DRAM size encoding (0 to 12) which is best for the combination
-	 * we have.
-	 *
-	 * First try if any of the possible alternatives matches exactly the amount
-	 * of memory we have.
-	 */
-
-	for (i = 0; bits == -1 && i < 13; i++)
-	{
-		bits = i;
-
-		for (j = 0; bits != -1 && j < 4; j++)
-			if (mem_decode[i][j] != bank_sizes[j])
-				bits = -1;	/* No hit */
-	}
-
-	/*
-	 * If necessary, try to find a combination where other than the last
-	 * bank matches our configuration and the last bank is left oversized.
-	 * In this way we don't leave holes in the middle of memory.
-	 */
-
-	if (bits == -1)		/* No luck yet */
-	{
-		for (i = 0; bits == -1 && i < 13; i++)
-		{
-			bits = i;
-
-			for (j = 0; bits != -1 && j < nbanks - 1; j++)
-				if (mem_decode[i][j] != bank_sizes[j])
-					bits = -1;	/* No hit */
-			if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1])
-				bits = -1;	/* The last bank is too small */
-		}
-	}
-	/*
- 	 * The last resort is to search for a combination where the banks are
- 	 * smaller than the actual SIMMs. This leaves some memory in the banks
- 	 * unused but doesn't leave holes in the DRAM address space.
- 	 */
- 	if (bits == -1)		/* No luck yet */
- 	{
- 		for (i = 0; i < 13; i++)
- 		{
- 			testbits = i;
- 			for (j = 0; testbits != -1 && j < nbanks - 1; j++)
- 				if (mem_decode[i][j] > bank_sizes[j]) {
- 					testbits = -1;
- 				}
- 			if(testbits > bits) bits = testbits;
- 		}
- 		if (bits != -1)
- 		{
-			printk(KERN_INFO "Interwave: Can't use all installed RAM.\n");
-			printk(KERN_INFO "Interwave: Try reordering SIMMS.\n");
-		}
-		printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n");
-		printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n");
-		bits = 0;
-	}
-	DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits));
-
-	for (bank = 0; bank < 4; bank++)
-	{
-		DDB(printk("  Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024));
-
-		if (bank_sizes[bank] > mem_decode[bits][bank])
-			total += mem_decode[bits][bank];
-		else
-			total += bank_sizes[bank];
-	}
-
-	DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024));
-
-	/*
-	 *    Set the memory addressing mode.
-	 */
-	gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits);
-
-/*      Leave the chip into enhanced mode. Disable LFO  */
-	gus_mem_size = total;
-	iw_mode = 1;
-	gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02);
-}
-
-int __init gus_wave_detect(int baseaddr)
-{
-	unsigned long   i, max_mem = 1024L;
-	unsigned long   loc;
-	unsigned char   val;
-
-	if (!request_region(baseaddr, 16, "GUS"))
-		return 0;
-	if (!request_region(baseaddr + 0x100, 12, "GUS")) { /* 0x10c-> is MAX */
-		release_region(baseaddr, 16);
-		return 0;
-	}
-
-	gus_base = baseaddr;
-
-	gus_write8(0x4c, 0);	/* Reset GF1 */
-	gus_delay();
-	gus_delay();
-
-	gus_write8(0x4c, 1);	/* Release Reset */
-	gus_delay();
-	gus_delay();
-
-#ifdef GUSPNP_AUTODETECT
-	val = gus_look8(0x5b);	/* Version number register */
-	gus_write8(0x5b, ~val);	/* Invert all bits */
-
-	if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0))	/* No change */
-	{
-		if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f))	/* Change */
-		{
-			DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
-			gus_pnp_flag = 1;
-		}
-		else
-		{
-			DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b)));
-			gus_pnp_flag = 0;
-		}
-	}
-	gus_write8(0x5b, val);	/* Restore all bits */
-#endif
-
-	if (gus_pnp_flag)
-		pnp_mem_init();
-	if (iw_mode)
-		return 1;
-
-	/* See if there is first block there.... */
-	gus_poke(0L, 0xaa);
-	if (gus_peek(0L) != 0xaa) {
-		release_region(baseaddr + 0x100, 12);
-		release_region(baseaddr, 16);
-		return 0;
-	}
-
-	/* Now zero it out so that I can check for mirroring .. */
-	gus_poke(0L, 0x00);
-	for (i = 1L; i < max_mem; i++)
-	{
-		int n, failed;
-
-		/* check for mirroring ... */
-		if (gus_peek(0L) != 0)
-			break;
-		loc = i << 10;
-
-		for (n = loc - 1, failed = 0; n <= loc; n++)
-		{
-			gus_poke(loc, 0xaa);
-			if (gus_peek(loc) != 0xaa)
-				failed = 1;
-			gus_poke(loc, 0x55);
-			if (gus_peek(loc) != 0x55)
-				failed = 1;
-		}
-		if (failed)
-			break;
-	}
-	gus_mem_size = i << 10;
-	return 1;
-}
-
-static int guswave_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
-
-	switch (cmd) 
-	{
-		case SNDCTL_SYNTH_INFO:
-			gus_info.nr_voices = nr_voices;
-			if (copy_to_user(arg, &gus_info, sizeof(gus_info)))
-				return -EFAULT;
-			return 0;
-
-		case SNDCTL_SEQ_RESETSAMPLES:
-			reset_sample_memory();
-			return 0;
-
-		case SNDCTL_SEQ_PERCMODE:
-			return 0;
-
-		case SNDCTL_SYNTH_MEMAVL:
-			return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
-
-		default:
-			return -EINVAL;
-	}
-}
-
-static int guswave_set_instr(int dev, int voice, int instr_no)
-{
-	int sample_no;
-
-	if (instr_no < 0 || instr_no > MAX_PATCH)
-		instr_no = 0;	/* Default to acoustic piano */
-
-	if (voice < 0 || voice > 31)
-		return -EINVAL;
-
-	if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
-	{
-		voices[voice].sample_pending = instr_no;
-		return 0;
-	}
-	sample_no = patch_table[instr_no];
-	patch_map[voice] = -1;
-
-	if (sample_no == NOT_SAMPLE)
-	{
-/*		printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/
-		return -EINVAL;	/* Patch not defined */
-	}
-	if (sample_ptrs[sample_no] == -1)	/* Sample not loaded */
-	{
-/*		printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/
-		return -EINVAL;
-	}
-	sample_map[voice] = sample_no;
-	patch_map[voice] = instr_no;
-	return 0;
-}
-
-static int guswave_kill_note(int dev, int voice, int note, int velocity)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&gus_lock,flags);
-	/* voice_alloc->map[voice] = 0xffff; */
-	if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
-	{
-		voices[voice].kill_pending = 1;
-		spin_unlock_irqrestore(&gus_lock,flags);
-	}
-	else
-	{
-		spin_unlock_irqrestore(&gus_lock,flags);
-		gus_voice_fade(voice);
-	}
-
-	return 0;
-}
-
-static void guswave_aftertouch(int dev, int voice, int pressure)
-{
-}
-
-static void guswave_panning(int dev, int voice, int value)
-{
-	if (voice >= 0 || voice < 32)
-		voices[voice].panning = value;
-}
-
-static void guswave_volume_method(int dev, int mode)
-{
-	if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
-		volume_method = mode;
-}
-
-static void compute_volume(int voice, int volume)
-{
-	if (volume < 128)
-		voices[voice].midi_volume = volume;
-
-	switch (volume_method)
-	{
-		case VOL_METHOD_ADAGIO:
-			voices[voice].initial_volume =
-				gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol,
-					voices[voice].expression_vol,
-					voices[voice].patch_vol);
-			break;
-
-		case VOL_METHOD_LINEAR:	/* Totally ignores patch-volume and expression */
-			voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol);
-			break;
-
-		default:
-			voices[voice].initial_volume = volume_base +
-				(voices[voice].midi_volume * volume_scale);
-	}
-
-	if (voices[voice].initial_volume > 4030)
-		voices[voice].initial_volume = 4030;
-}
-
-static void compute_and_set_volume(int voice, int volume, int ramp_time)
-{
-	int curr, target, rate;
-	unsigned long flags;
-
-	compute_volume(voice, volume);
-	voices[voice].current_volume = voices[voice].initial_volume;
-
-	spin_lock_irqsave(&gus_lock,flags);
-	/*
-	 * CAUTION! Interrupts disabled. Enable them before returning
-	 */
-
-	gus_select_voice(voice);
-
-	curr = gus_read16(0x09) >> 4;
-	target = voices[voice].initial_volume;
-
-	if (ramp_time == INSTANT_RAMP)
-	{
-		gus_rampoff();
-		gus_voice_volume(target);
-		spin_unlock_irqrestore(&gus_lock,flags);
-		return;
-	}
-	if (ramp_time == FAST_RAMP)
-		rate = 63;
-	else
-		rate = 16;
-	gus_ramp_rate(0, rate);
-
-	if ((target - curr) / 64 == 0)	/* Close enough to target. */
-	{
-		gus_rampoff();
-		gus_voice_volume(target);
-		spin_unlock_irqrestore(&gus_lock,flags);
-		return;
-	}
-	if (target > curr)
-	{
-		if (target > (4095 - 65))
-			target = 4095 - 65;
-		gus_ramp_range(curr, target);
-		gus_rampon(0x00);	/* Ramp up, once, no IRQ */
-	}
-	else
-	{
-		if (target < 65)
-			target = 65;
-
-		gus_ramp_range(target, curr);
-		gus_rampon(0x40);	/* Ramp down, once, no irq */
-	}
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void dynamic_volume_change(int voice)
-{
-	unsigned char status;
-	unsigned long flags;
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-	status = gus_read8(0x00);	/* Get voice status */
-	spin_unlock_irqrestore(&gus_lock,flags);
-
-	if (status & 0x03)
-		return;		/* Voice was not running */
-
-	if (!(voices[voice].mode & WAVE_ENVELOPES))
-	{
-		compute_and_set_volume(voice, voices[voice].midi_volume, 1);
-		return;
-	}
-	
-	/*
-	 * Voice is running and has envelopes.
-	 */
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-	status = gus_read8(0x0d);	/* Ramping status */
-	spin_unlock_irqrestore(&gus_lock,flags);
-
-	if (status & 0x03)	/* Sustain phase? */
-	{
-		compute_and_set_volume(voice, voices[voice].midi_volume, 1);
-		return;
-	}
-	if (voices[voice].env_phase < 0)
-		return;
-
-	compute_volume(voice, voices[voice].midi_volume);
-
-}
-
-static void guswave_controller(int dev, int voice, int ctrl_num, int value)
-{
-	unsigned long   flags;
-	unsigned long   freq;
-
-	if (voice < 0 || voice > 31)
-		return;
-
-	switch (ctrl_num)
-	{
-		case CTRL_PITCH_BENDER:
-			voices[voice].bender = value;
-
-			if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
-			{
-				freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0);
-				voices[voice].current_freq = freq;
-
-				spin_lock_irqsave(&gus_lock,flags);
-				gus_select_voice(voice);
-				gus_voice_freq(freq);
-				spin_unlock_irqrestore(&gus_lock,flags);
-			}
-			break;
-
-		case CTRL_PITCH_BENDER_RANGE:
-			voices[voice].bender_range = value;
-			break;
-		case CTL_EXPRESSION:
-			value /= 128;
-		case CTRL_EXPRESSION:
-			if (volume_method == VOL_METHOD_ADAGIO)
-			{
-				voices[voice].expression_vol = value;
-				if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
-					dynamic_volume_change(voice);
-			}
-			break;
-
-		case CTL_PAN:
-			voices[voice].panning = (value * 2) - 128;
-			break;
-
-		case CTL_MAIN_VOLUME:
-			value = (value * 100) / 16383;
-
-		case CTRL_MAIN_VOLUME:
-			voices[voice].main_vol = value;
-			if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
-				dynamic_volume_change(voice);
-			break;
-
-		default:
-			break;
-	}
-}
-
-static int guswave_start_note2(int dev, int voice, int note_num, int volume)
-{
-	int sample, best_sample, best_delta, delta_freq;
-	int is16bits, samplep, patch, pan;
-	unsigned long   note_freq, base_note, freq, flags;
-	unsigned char   mode = 0;
-
-	if (voice < 0 || voice > 31)
-	{
-/*		printk("GUS: Invalid voice\n");*/
-		return -EINVAL;
-	}
-	if (note_num == 255)
-	{
-		if (voices[voice].mode & WAVE_ENVELOPES)
-		{
-			voices[voice].midi_volume = volume;
-			dynamic_volume_change(voice);
-			return 0;
-		}
-		compute_and_set_volume(voice, volume, 1);
-		return 0;
-	}
-	if ((patch = patch_map[voice]) == -1)
-		return -EINVAL;
-	if ((samplep = patch_table[patch]) == NOT_SAMPLE)
-	{
-		return -EINVAL;
-	}
-	note_freq = note_to_freq(note_num);
-
-	/*
-	 * Find a sample within a patch so that the note_freq is between low_note
-	 * and high_note.
-	 */
-	sample = -1;
-
-	best_sample = samplep;
-	best_delta = 1000000;
-	while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1)
-	{
-		delta_freq = note_freq - samples[samplep].base_note;
-		if (delta_freq < 0)
-			delta_freq = -delta_freq;
-		if (delta_freq < best_delta)
-		{
-			best_sample = samplep;
-			best_delta = delta_freq;
-		}
-		if (samples[samplep].low_note <= note_freq &&
-			note_freq <= samples[samplep].high_note)
-		{
-			sample = samplep;
-		}
-		else
-			samplep = samples[samplep].key;	/* Link to next sample */
-	  }
-	if (sample == -1)
-		sample = best_sample;
-
-	if (sample == -1)
-	{
-/*		printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/
-		return 0;	/* Should play default patch ??? */
-	}
-	is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
-	voices[voice].mode = samples[sample].mode;
-	voices[voice].patch_vol = samples[sample].volume;
-
-	if (iw_mode)
-		gus_write8(0x15, 0x00);		/* RAM, Reset voice deactivate bit of SMSI */
-
-	if (voices[voice].mode & WAVE_ENVELOPES)
-	{
-		int i;
-
-		for (i = 0; i < 6; i++)
-		{
-			voices[voice].env_rate[i] = samples[sample].env_rate[i];
-			voices[voice].env_offset[i] = samples[sample].env_offset[i];
-		}
-	}
-	sample_map[voice] = sample;
-
-	if (voices[voice].fixed_pitch)	/* Fixed pitch */
-	{
-		  freq = samples[sample].base_freq;
-	}
-	else
-	{
-		base_note = samples[sample].base_note / 100;
-		note_freq /= 100;
-
-		freq = samples[sample].base_freq * note_freq / base_note;
-	}
-
-	voices[voice].orig_freq = freq;
-
-	/*
-	 * Since the pitch bender may have been set before playing the note, we
-	 * have to calculate the bending now.
-	 */
-
-	freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender,
-				voices[voice].bender_range, 0);
-	voices[voice].current_freq = freq;
-
-	pan = (samples[sample].panning + voices[voice].panning) / 32;
-	pan += 7;
-	if (pan < 0)
-		pan = 0;
-	if (pan > 15)
-		pan = 15;
-
-	if (samples[sample].mode & WAVE_16_BITS)
-	{
-		mode |= 0x04;	/* 16 bits */
-		if ((sample_ptrs[sample] / GUS_BANK_SIZE) !=
-			((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))
-				printk(KERN_ERR "GUS: Sample address error\n");
-	}
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-	gus_voice_off();
-	gus_rampoff();
-
-	spin_unlock_irqrestore(&gus_lock,flags);
-
-	if (voices[voice].mode & WAVE_ENVELOPES)
-	{
-		compute_volume(voice, volume);
-		init_envelope(voice);
-	}
-	else
-	{
-		compute_and_set_volume(voice, volume, 0);
-	}
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-
-	if (samples[sample].mode & WAVE_LOOP_BACK)
-		gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -
-			voices[voice].offset_pending, 0, is16bits);	/* start=end */
-	else
-		gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits);	/* Sample start=begin */
-
-	if (samples[sample].mode & WAVE_LOOPING)
-	{
-		mode |= 0x08;
-
-		if (samples[sample].mode & WAVE_BIDIR_LOOP)
-			mode |= 0x10;
-
-		if (samples[sample].mode & WAVE_LOOP_BACK)
-		{
-			gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end -
-					   voices[voice].offset_pending,
-					   (samples[sample].fractions >> 4) & 0x0f, is16bits);
-			mode |= 0x40;
-		}
-		gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start,
-			samples[sample].fractions & 0x0f, is16bits);	/* Loop start location */
-		gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end,
-			(samples[sample].fractions >> 4) & 0x0f, is16bits);	/* Loop end location */
-	}
-	else
-	{
-		mode |= 0x20;	/* Loop IRQ at the end */
-		voices[voice].loop_irq_mode = LMODE_FINISH;	/* Ramp down at the end */
-		voices[voice].loop_irq_parm = 1;
-		gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits);	/* Loop start location */
-		gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1,
-			(samples[sample].fractions >> 4) & 0x0f, is16bits);	/* Loop end location */
-	}
-	gus_voice_freq(freq);
-	gus_voice_balance(pan);
-	gus_voice_on(mode);
-	spin_unlock_irqrestore(&gus_lock,flags);
-
-	return 0;
-}
-
-/*
- * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
- * when the note playing on the voice is changed.  It uses volume
- * ramping.
- */
-
-static int guswave_start_note(int dev, int voice, int note_num, int volume)
-{
-	unsigned long flags;
-	int mode;
-	int ret_val = 0;
-
-	spin_lock_irqsave(&gus_lock,flags);
-	if (note_num == 255)
-	{
-		if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
-		{
-			voices[voice].volume_pending = volume;
-		}
-		else
-		{
-			ret_val = guswave_start_note2(dev, voice, note_num, volume);
-		}
-	}
-	else
-	{
-		gus_select_voice(voice);
-		mode = gus_read8(0x00);
-		if (mode & 0x20)
-			gus_write8(0x00, mode & 0xdf);	/* No interrupt! */
-
-		voices[voice].offset_pending = 0;
-		voices[voice].kill_pending = 0;
-		voices[voice].volume_irq_mode = 0;
-		voices[voice].loop_irq_mode = 0;
-
-		if (voices[voice].sample_pending >= 0)
-		{
-			spin_unlock_irqrestore(&gus_lock,flags);	/* Run temporarily with interrupts enabled */
-			guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending);
-			voices[voice].sample_pending = -1;
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);	/* Reselect the voice (just to be sure) */
-		}
-		if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065))
-		{
-			ret_val = guswave_start_note2(dev, voice, note_num, volume);
-		}
-		else
-		{
-			voices[voice].dev_pending = dev;
-			voices[voice].note_pending = note_num;
-			voices[voice].volume_pending = volume;
-			voices[voice].volume_irq_mode = VMODE_START_NOTE;
-
-			gus_rampoff();
-			gus_ramp_range(2000, 4065);
-			gus_ramp_rate(0, 63);	/* Fastest possible rate */
-			gus_rampon(0x20 | 0x40);	/* Ramp down, once, irq */
-		}
-	}
-	spin_unlock_irqrestore(&gus_lock,flags);
-	return ret_val;
-}
-
-static void guswave_reset(int dev)
-{
-	int i;
-
-	for (i = 0; i < 32; i++)
-	{
-		gus_voice_init(i);
-		gus_voice_init2(i);
-	}
-}
-
-static int guswave_open(int dev, int mode)
-{
-	int err;
-
-	if (gus_busy)
-		return -EBUSY;
-
-	voice_alloc->timestamp = 0;
-
-	if (gus_no_wave_dma) {
-		gus_no_dma = 1;
-	} else {
-		if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
-		{
-			/* printk( "GUS: Loading samples without DMA\n"); */
-			gus_no_dma = 1;	/* Upload samples using PIO */
-		}
-		else
-			gus_no_dma = 0;
-	}
-
-	init_waitqueue_head(&dram_sleeper);
-	gus_busy = 1;
-	active_device = GUS_DEV_WAVE;
-
-	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
-	gus_initialize();
-	gus_reset();
-	gusintr(gus_irq, (void *)gus_hw_config, NULL);	/* Serve pending interrupts */
-
-	return 0;
-}
-
-static void guswave_close(int dev)
-{
-	gus_busy = 0;
-	active_device = 0;
-	gus_reset();
-
-	if (!gus_no_dma)
-		DMAbuf_close_dma(gus_devnum);
-}
-
-static int guswave_load_patch(int dev, int format, const char __user *addr,
-		   int offs, int count, int pmgr_flag)
-{
-	struct patch_info patch;
-	int instr;
-	long sizeof_patch;
-
-	unsigned long blk_sz, blk_end, left, src_offs, target;
-
-	sizeof_patch = (long) &patch.data[0] - (long) &patch;	/* Header size */
-
-	if (format != GUS_PATCH)
-	{
-/*		printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/
-		return -EINVAL;
-	}
-	if (count < sizeof_patch)
-	{
-/*		  printk("GUS Error: Patch header too short\n");*/
-		  return -EINVAL;
-	}
-	count -= sizeof_patch;
-
-	if (free_sample >= MAX_SAMPLE)
-	{
-/*		  printk("GUS: Sample table full\n");*/
-		  return -ENOSPC;
-	}
-	/*
-	 * Copy the header from user space but ignore the first bytes which have
-	 * been transferred already.
-	 */
-
-	if (copy_from_user(&((char *) &patch)[offs], &(addr)[offs],
-			   sizeof_patch - offs))
-		return -EFAULT;
-
-	if (patch.mode & WAVE_ROM)
-		return -EINVAL;
-	if (gus_mem_size == 0)
-		return -ENOSPC;
-
-	instr = patch.instr_no;
-
-	if (instr < 0 || instr > MAX_PATCH)
-	{
-/*		printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/
-		return -EINVAL;
-	}
-	if (count < patch.len)
-	{
-/*		printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/
-		patch.len = count;
-	}
-	if (patch.len <= 0 || patch.len > gus_mem_size)
-	{
-/*		printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/
-		return -EINVAL;
-	}
-	if (patch.mode & WAVE_LOOPING)
-	{
-		if (patch.loop_start < 0 || patch.loop_start >= patch.len)
-		{
-/*			printk(KERN_ERR "GUS: Invalid loop start\n");*/
-			return -EINVAL;
-		}
-		if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
-		{
-/*			printk(KERN_ERR "GUS: Invalid loop end\n");*/
-			return -EINVAL;
-		}
-	}
-	free_mem_ptr = (free_mem_ptr + 31) & ~31;	/* 32 byte alignment */
-
-	if (patch.mode & WAVE_16_BITS)
-	{
-		/*
-		 * 16 bit samples must fit one 256k bank.
-		 */
-		if (patch.len >= GUS_BANK_SIZE)
-		{
-/*			 printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/
-			return -ENOSPC;
-		}
-		if ((free_mem_ptr / GUS_BANK_SIZE) !=
-			((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
-		{
-			unsigned long   tmp_mem =	
-				/* Align to 256K */
-					((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
-
-			if ((tmp_mem + patch.len) > gus_mem_size)
-				return -ENOSPC;
-
-			free_mem_ptr = tmp_mem;		/* This leaves unusable memory */
-		}
-	}
-	if ((free_mem_ptr + patch.len) > gus_mem_size)
-		return -ENOSPC;
-
-	sample_ptrs[free_sample] = free_mem_ptr;
-
-	/*
-	 * Tremolo is not possible with envelopes
-	 */
-
-	if (patch.mode & WAVE_ENVELOPES)
-		patch.mode &= ~WAVE_TREMOLO;
-
-	if (!(patch.mode & WAVE_FRACTIONS))
-	{
-		  patch.fractions = 0;
-	}
-	memcpy((char *) &samples[free_sample], &patch, sizeof_patch);
-
-	/*
-	 * Link this_one sample to the list of samples for patch 'instr'.
-	 */
-
-	samples[free_sample].key = patch_table[instr];
-	patch_table[instr] = free_sample;
-
-	/*
-	 * Use DMA to transfer the wave data to the DRAM
-	 */
-
-	left = patch.len;
-	src_offs = 0;
-	target = free_mem_ptr;
-
-	while (left)		/* Not completely transferred yet */
-	{
-		blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
-		if (blk_sz > left)
-			blk_sz = left;
-
-		/*
-		 * DMA cannot cross bank (256k) boundaries. Check for that.
-		 */
-		 
-		blk_end = target + blk_sz;
-
-		if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE))
-		{
-			/* Split the block */
-			blk_end &= ~(GUS_BANK_SIZE - 1);
-			blk_sz = blk_end - target;
-		}
-		if (gus_no_dma)
-		{
-			/*
-			 * For some reason the DMA is not possible. We have to use PIO.
-			 */
-			long i;
-			unsigned char data;
-
-			for (i = 0; i < blk_sz; i++)
-			{
-				get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[sizeof_patch + i]));
-				if (patch.mode & WAVE_UNSIGNED)
-					if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
-						data ^= 0x80;	/* Convert to signed */
-				gus_poke(target + i, data);
-			}
-		}
-		else
-		{
-			unsigned long address, hold_address;
-			unsigned char dma_command;
-			unsigned long flags;
-
-			if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)
-			{
-				printk(KERN_ERR "GUS: DMA buffer == NULL\n");
-				return -ENOSPC;
-			}
-			/*
-			 * OK, move now. First in and then out.
-			 */
-
-			if (copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf,
-					   &(addr)[sizeof_patch + src_offs],
-					   blk_sz))
-				return -EFAULT;
-
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_write8(0x41, 0);	/* Disable GF1 DMA */
-			DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
-				blk_sz, DMA_MODE_WRITE);
-
-			/*
-			 * Set the DRAM address for the wave data
-			 */
-
-			if (iw_mode)
-			{
-				/* Different address translation in enhanced mode */
-
-				unsigned char   hi;
-
-				if (gus_dma > 4)
-					address = target >> 1;	/* Convert to 16 bit word address */
-				else
-					address = target;
-
-				hi = (unsigned char) ((address >> 16) & 0xf0);
-				hi += (unsigned char) (address & 0x0f);
-
-				gus_write16(0x42, (address >> 4) & 0xffff);	/* DMA address (low) */
-				gus_write8(0x50, hi);
-			}
-			else
-			{
-				address = target;
-				if (audio_devs[gus_devnum]->dmap_out->dma > 3)
-				{
-					hold_address = address;
-					address = address >> 1;
-					address &= 0x0001ffffL;
-					address |= (hold_address & 0x000c0000L);
-				}
-				gus_write16(0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
-			}
-
-			/*
-			 * Start the DMA transfer
-			 */
-
-			dma_command = 0x21;		/* IRQ enable, DMA start */
-			if (patch.mode & WAVE_UNSIGNED)
-				dma_command |= 0x80;	/* Invert MSB */
-			if (patch.mode & WAVE_16_BITS)
-				dma_command |= 0x40;	/* 16 bit _DATA_ */
-			if (audio_devs[gus_devnum]->dmap_out->dma > 3)
-				dma_command |= 0x04;	/* 16 bit DMA _channel_ */
-			
-			/*
-			 * Sleep here until the DRAM DMA done interrupt is served
-			 */
-			active_device = GUS_DEV_WAVE;
-			gus_write8(0x41, dma_command);	/* Lets go luteet (=bugs) */
-
-			spin_unlock_irqrestore(&gus_lock,flags); /* opens a race */
-			if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
-				printk("GUS: DMA Transfer timed out\n");
-		}
-
-		/*
-		 * Now the next part
-		 */
-
-		left -= blk_sz;
-		src_offs += blk_sz;
-		target += blk_sz;
-
-		gus_write8(0x41, 0);	/* Stop DMA */
-	}
-
-	free_mem_ptr += patch.len;
-	free_sample++;
-	return 0;
-}
-
-static void guswave_hw_control(int dev, unsigned char *event_rec)
-{
-	int voice, cmd;
-	unsigned short p1, p2;
-	unsigned int plong;
-	unsigned long flags;
-
-	cmd = event_rec[2];
-	voice = event_rec[3];
-	p1 = *(unsigned short *) &event_rec[4];
-	p2 = *(unsigned short *) &event_rec[6];
-	plong = *(unsigned int *) &event_rec[4];
-
-	if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
-		(cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
-		do_volume_irq(voice);
-
-	switch (cmd)
-	{
-		case _GUS_NUMVOICES:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_select_max_voices(p1);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOICESAMPLE:
-			guswave_set_instr(dev, voice, p1);
-			break;
-
-		case _GUS_VOICEON:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			p1 &= ~0x20;	/* Don't allow interrupts */
-			gus_voice_on(p1);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOICEOFF:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_voice_off();
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOICEFADE:
-			gus_voice_fade(voice);
-			break;
-
-		case _GUS_VOICEMODE:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			p1 &= ~0x20;	/* Don't allow interrupts */
-			gus_voice_mode(p1);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOICEBALA:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_voice_balance(p1);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOICEFREQ:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_voice_freq(plong);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOICEVOL:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_voice_volume(p1);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOICEVOL2:	/* Just update the software voice level */
-			voices[voice].initial_volume = voices[voice].current_volume = p1;
-			break;
-
-		case _GUS_RAMPRANGE:
-			if (voices[voice].mode & WAVE_ENVELOPES)
-				break;	/* NO-NO */
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_ramp_range(p1, p2);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_RAMPRATE:
-			if (voices[voice].mode & WAVE_ENVELOPES)
-				break;	/* NJET-NJET */
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_ramp_rate(p1, p2);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_RAMPMODE:
-			if (voices[voice].mode & WAVE_ENVELOPES)
-				break;	/* NO-NO */
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			p1 &= ~0x20;	/* Don't allow interrupts */
-			gus_ramp_mode(p1);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_RAMPON:
-			if (voices[voice].mode & WAVE_ENVELOPES)
-				break;	/* EI-EI */
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			p1 &= ~0x20;	/* Don't allow interrupts */
-			gus_rampon(p1);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_RAMPOFF:
-			if (voices[voice].mode & WAVE_ENVELOPES)
-				break;	/* NEJ-NEJ */
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_rampoff();
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		case _GUS_VOLUME_SCALE:
-			volume_base = p1;
-			volume_scale = p2;
-			break;
-
-		case _GUS_VOICE_POS:
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_set_voice_pos(voice, plong);
-			spin_unlock_irqrestore(&gus_lock,flags);
-			break;
-
-		default:
-			break;
-	}
-}
-
-static int gus_audio_set_speed(int speed)
-{
-	if (speed <= 0)
-		speed = gus_audio_speed;
-
-	if (speed < 4000)
-		speed = 4000;
-
-	if (speed > 44100)
-		speed = 44100;
-
-	gus_audio_speed = speed;
-
-	if (only_read_access)
-	{
-		/* Compute nearest valid recording speed  and return it */
-
-		/* speed = (9878400 / (gus_audio_speed + 2)) / 16; */
-		speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
-		speed = (9878400 / (speed * 16)) - 2;
-	}
-	return speed;
-}
-
-static int gus_audio_set_channels(int channels)
-{
-	if (!channels)
-		return gus_audio_channels;
-	if (channels > 2)
-		channels = 2;
-	if (channels < 1)
-		channels = 1;
-	gus_audio_channels = channels;
-	return channels;
-}
-
-static int gus_audio_set_bits(int bits)
-{
-	if (!bits)
-		return gus_audio_bits;
-
-	if (bits != 8 && bits != 16)
-		bits = 8;
-
-	if (only_8_bits)
-		bits = 8;
-
-	gus_audio_bits = bits;
-	return bits;
-}
-
-static int gus_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
-	int val;
-
-	switch (cmd) 
-	{
-		case SOUND_PCM_WRITE_RATE:
-			if (get_user(val, (int __user*)arg))
-				return -EFAULT;
-			val = gus_audio_set_speed(val);
-			break;
-
-		case SOUND_PCM_READ_RATE:
-			val = gus_audio_speed;
-			break;
-
-		case SNDCTL_DSP_STEREO:
-			if (get_user(val, (int __user *)arg))
-				return -EFAULT;
-			val = gus_audio_set_channels(val + 1) - 1;
-			break;
-
-		case SOUND_PCM_WRITE_CHANNELS:
-			if (get_user(val, (int __user *)arg))
-				return -EFAULT;
-			val = gus_audio_set_channels(val);
-			break;
-
-		case SOUND_PCM_READ_CHANNELS:
-			val = gus_audio_channels;
-			break;
-		
-		case SNDCTL_DSP_SETFMT:
-			if (get_user(val, (int __user *)arg))
-				return -EFAULT;
-			val = gus_audio_set_bits(val);
-			break;
-		
-		case SOUND_PCM_READ_BITS:
-			val = gus_audio_bits;
-			break;
-		
-		case SOUND_PCM_WRITE_FILTER:		/* NOT POSSIBLE */
-		case SOUND_PCM_READ_FILTER:
-			val = -EINVAL;
-			break;
-		default:
-			return -EINVAL;
-	}
-	return put_user(val, (int __user *)arg);
-}
-
-static void gus_audio_reset(int dev)
-{
-	if (recording_active)
-	{
-		gus_write8(0x49, 0x00);	/* Halt recording */
-		set_input_volumes();
-	}
-}
-
-static int saved_iw_mode;	/* A hack hack hack */
-
-static int gus_audio_open(int dev, int mode)
-{
-	if (gus_busy)
-		return -EBUSY;
-
-	if (gus_pnp_flag && mode & OPEN_READ)
-	{
-/*		printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/
-		return -EIO;
-	}
-	gus_initialize();
-
-	gus_busy = 1;
-	active_device = 0;
-
-	saved_iw_mode = iw_mode;
-	if (iw_mode)
-	{
-		/* There are some problems with audio in enhanced mode so disable it */
-		gus_write8(0x19, gus_read8(0x19) & ~0x01);	/* Disable enhanced mode */
-		iw_mode = 0;
-	}
-
-	gus_reset();
-	reset_sample_memory();
-	gus_select_max_voices(14);
-
-	pcm_active = 0;
-	dma_active = 0;
-	pcm_opened = 1;
-	if (mode & OPEN_READ)
-	{
-		recording_active = 1;
-		set_input_volumes();
-	}
-	only_read_access = !(mode & OPEN_WRITE);
-	only_8_bits = mode & OPEN_READ;
-	if (only_8_bits)
-		audio_devs[dev]->format_mask = AFMT_U8;
-	else
-		audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;
-
-	return 0;
-}
-
-static void gus_audio_close(int dev)
-{
-	iw_mode = saved_iw_mode;
-	gus_reset();
-	gus_busy = 0;
-	pcm_opened = 0;
-	active_device = 0;
-
-	if (recording_active)
-	{
-		gus_write8(0x49, 0x00);	/* Halt recording */
-		set_input_volumes();
-	}
-	recording_active = 0;
-}
-
-static void gus_audio_update_volume(void)
-{
-	unsigned long flags;
-	int voice;
-
-	if (pcm_active && pcm_opened)
-		for (voice = 0; voice < gus_audio_channels; voice++)
-		{
-			spin_lock_irqsave(&gus_lock,flags);
-			gus_select_voice(voice);
-			gus_rampoff();
-			gus_voice_volume(1530 + (25 * gus_pcm_volume));
-			gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
-			spin_unlock_irqrestore(&gus_lock,flags);
-		}
-}
-
-static void play_next_pcm_block(void)
-{
-	unsigned long flags;
-	int speed = gus_audio_speed;
-	int this_one, is16bits, chn;
-	unsigned long dram_loc;
-	unsigned char mode[2], ramp_mode[2];
-
-	if (!pcm_qlen)
-		return;
-
-	this_one = pcm_head;
-
-	for (chn = 0; chn < gus_audio_channels; chn++)
-	{
-		mode[chn] = 0x00;
-		ramp_mode[chn] = 0x03;	/* Ramping and rollover off */
-
-		if (chn == 0)
-		{
-			mode[chn] |= 0x20;	/* Loop IRQ */
-			voices[chn].loop_irq_mode = LMODE_PCM;
-		}
-		if (gus_audio_bits != 8)
-		{
-			is16bits = 1;
-			mode[chn] |= 0x04;	/* 16 bit data */
-		}
-		else
-			is16bits = 0;
-
-		dram_loc = this_one * pcm_bsize;
-		dram_loc += chn * pcm_banksize;
-
-		if (this_one == (pcm_nblk - 1))	/* Last fragment of the DRAM buffer */
-		{
-			mode[chn] |= 0x08;	/* Enable loop */
-			ramp_mode[chn] = 0x03;	/* Disable rollover bit */
-		}
-		else
-		{
-			if (chn == 0)
-				ramp_mode[chn] = 0x04;	/* Enable rollover bit */
-		}
-		spin_lock_irqsave(&gus_lock,flags);
-		gus_select_voice(chn);
-		gus_voice_freq(speed);
-
-		if (gus_audio_channels == 1)
-			gus_voice_balance(7);		/* mono */
-		else if (chn == 0)
-			gus_voice_balance(0);		/* left */
-		else
-			gus_voice_balance(15);		/* right */
-
-		if (!pcm_active)	/* Playback not already active */
-		{
-			/*
-			 * The playback was not started yet (or there has been a pause).
-			 * Start the voice (again) and ask for a rollover irq at the end of
-			 * this_one block. If this_one one is last of the buffers, use just
-			 * the normal loop with irq.
-			 */
-
-			gus_voice_off();
-			gus_rampoff();
-			gus_voice_volume(1530 + (25 * gus_pcm_volume));
-			gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
-
-			gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits);	/* Starting position */
-			gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits);	/* Loop start */
-
-			if (chn != 0)
-				gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
-						   0, is16bits);	/* Loop end location */
-		}
-		if (chn == 0)
-			gus_write_addr(0x04, dram_loc + pcm_bsize - 1,
-					 0, is16bits);	/* Loop end location */
-		else
-			mode[chn] |= 0x08;	/* Enable looping */
-		spin_unlock_irqrestore(&gus_lock,flags);
-	}
-	for (chn = 0; chn < gus_audio_channels; chn++)
-	{
-		spin_lock_irqsave(&gus_lock,flags);
-		gus_select_voice(chn);
-		gus_write8(0x0d, ramp_mode[chn]);
-		if (iw_mode)
-			gus_write8(0x15, 0x00);	/* Reset voice deactivate bit of SMSI */
-		gus_voice_on(mode[chn]);
-		spin_unlock_irqrestore(&gus_lock,flags);
-	}
-	pcm_active = 1;
-}
-
-static void gus_transfer_output_block(int dev, unsigned long buf,
-			  int total_count, int intrflag, int chn)
-{
-	/*
-	 * This routine transfers one block of audio data to the DRAM. In mono mode
-	 * it's called just once. When in stereo mode, this_one routine is called
-	 * once for both channels.
-	 *
-	 * The left/mono channel data is transferred to the beginning of dram and the
-	 * right data to the area pointed by gus_page_size.
-	 */
-
-	int this_one, count;
-	unsigned long flags;
-	unsigned char dma_command;
-	unsigned long address, hold_address;
-
-	spin_lock_irqsave(&gus_lock,flags);
-
-	count = total_count / gus_audio_channels;
-
-	if (chn == 0)
-	{
-		if (pcm_qlen >= pcm_nblk)
-			printk(KERN_WARNING "GUS Warning: PCM buffers out of sync\n");
-
-		this_one = pcm_current_block = pcm_tail;
-		pcm_qlen++;
-		pcm_tail = (pcm_tail + 1) % pcm_nblk;
-		pcm_datasize[this_one] = count;
-	}
-	else
-		this_one = pcm_current_block;
-
-	gus_write8(0x41, 0);	/* Disable GF1 DMA */
-	DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE);
-
-	address = this_one * pcm_bsize;
-	address += chn * pcm_banksize;
-
-	if (audio_devs[dev]->dmap_out->dma > 3)
-	{
-		hold_address = address;
-		address = address >> 1;
-		address &= 0x0001ffffL;
-		address |= (hold_address & 0x000c0000L);
-	}
-	gus_write16(0x42, (address >> 4) & 0xffff);	/* DRAM DMA address */
-
-	dma_command = 0x21;	/* IRQ enable, DMA start */
-
-	if (gus_audio_bits != 8)
-		dma_command |= 0x40;	/* 16 bit _DATA_ */
-	else
-		dma_command |= 0x80;	/* Invert MSB */
-
-	if (audio_devs[dev]->dmap_out->dma > 3)
-		dma_command |= 0x04;	/* 16 bit DMA channel */
-
-	gus_write8(0x41, dma_command);	/* Kick start */
-
-	if (chn == (gus_audio_channels - 1))	/* Last channel */
-	{
-		/*
-		 * Last (right or mono) channel data
-		 */
-		dma_active = 1;	/* DMA started. There is a unacknowledged buffer */
-		active_device = GUS_DEV_PCM_DONE;
-		if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize))
-		{
-			play_next_pcm_block();
-		}
-	}
-	else
-	{
-		/*
-		 * Left channel data. The right channel
-		 * is transferred after DMA interrupt
-		 */
-		active_device = GUS_DEV_PCM_CONTINUE;
-	}
-
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void gus_uninterleave8(char *buf, int l)
-{
-/* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */
-	int i, p = 0, halfsize = l / 2;
-	char *buf2 = buf + halfsize, *src = bounce_buf;
-
-	memcpy(bounce_buf, buf, l);
-
-	for (i = 0; i < halfsize; i++)
-	{
-		buf[i] = src[p++];	/* Left channel */
-		buf2[i] = src[p++];	/* Right channel */
-	}
-}
-
-static void gus_uninterleave16(short *buf, int l)
-{
-/* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */
-	int i, p = 0, halfsize = l / 2;
-	short *buf2 = buf + halfsize, *src = (short *) bounce_buf;
-
-	memcpy(bounce_buf, (char *) buf, l * 2);
-
-	for (i = 0; i < halfsize; i++)
-	{
-		buf[i] = src[p++];	/* Left channel */
-		buf2[i] = src[p++];	/* Right channel */
-	}
-}
-
-static void gus_audio_output_block(int dev, unsigned long buf, int total_count,
-		       int intrflag)
-{
-	struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-	dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT;
-
-	pcm_current_buf = buf;
-	pcm_current_count = total_count;
-	pcm_current_intrflag = intrflag;
-	pcm_current_dev = dev;
-	if (gus_audio_channels == 2)
-	{
-		char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys);
-
-		if (gus_audio_bits == 8)
-			gus_uninterleave8(b, total_count);
-		else
-			gus_uninterleave16((short *) b, total_count / 2);
-	}
-	gus_transfer_output_block(dev, buf, total_count, intrflag, 0);
-}
-
-static void gus_audio_start_input(int dev, unsigned long buf, int count,
-		      int intrflag)
-{
-	unsigned long flags;
-	unsigned char mode;
-
-	spin_lock_irqsave(&gus_lock,flags);
-
-	DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ);
-	mode = 0xa0;		/* DMA IRQ enabled, invert MSB */
-
-	if (audio_devs[dev]->dmap_in->dma > 3)
-		mode |= 0x04;	/* 16 bit DMA channel */
-	if (gus_audio_channels > 1)
-		mode |= 0x02;	/* Stereo */
-	mode |= 0x01;		/* DMA enable */
-
-	gus_write8(0x49, mode);
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int gus_audio_prepare_for_input(int dev, int bsize, int bcount)
-{
-	unsigned int rate;
-
-	gus_audio_bsize = bsize;
-	audio_devs[dev]->dmap_in->flags |= DMA_NODMA;
-	rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
-
-	gus_write8(0x48, rate & 0xff);	/* Set sampling rate */
-
-	if (gus_audio_bits != 8)
-	{
-/*		printk("GUS Error: 16 bit recording not supported\n");*/
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int gus_audio_prepare_for_output(int dev, int bsize, int bcount)
-{
-	int i;
-
-	long mem_ptr, mem_size;
-
-	audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT;
-	mem_ptr = 0;
-	mem_size = gus_mem_size / gus_audio_channels;
-
-	if (mem_size > (256 * 1024))
-		mem_size = 256 * 1024;
-
-	pcm_bsize = bsize / gus_audio_channels;
-	pcm_head = pcm_tail = pcm_qlen = 0;
-
-	pcm_nblk = 2;		/* MAX_PCM_BUFFERS; */
-	if ((pcm_bsize * pcm_nblk) > mem_size)
-		pcm_nblk = mem_size / pcm_bsize;
-
-	for (i = 0; i < pcm_nblk; i++)
-		pcm_datasize[i] = 0;
-
-	pcm_banksize = pcm_nblk * pcm_bsize;
-
-	if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024))
-		pcm_nblk--;
-	gus_write8(0x41, 0);	/* Disable GF1 DMA */
-	return 0;
-}
-
-static int gus_local_qlen(int dev)
-{
-	return pcm_qlen;
-}
-
-
-static struct audio_driver gus_audio_driver =
-{
-	.owner			= THIS_MODULE,
-	.open			= gus_audio_open,
-	.close			= gus_audio_close,
-	.output_block		= gus_audio_output_block,
-	.start_input		= gus_audio_start_input,
-	.ioctl			= gus_audio_ioctl,
-	.prepare_for_input	= gus_audio_prepare_for_input,
-	.prepare_for_output	= gus_audio_prepare_for_output,
-	.halt_io		= gus_audio_reset,
-	.local_qlen		= gus_local_qlen,
-};
-
-static void guswave_setup_voice(int dev, int voice, int chn)
-{
-	struct channel_info *info = &synth_devs[dev]->chn_info[chn];
-
-	guswave_set_instr(dev, voice, info->pgm_num);
-	voices[voice].expression_vol = info->controllers[CTL_EXPRESSION];	/* Just MSB */
-	voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
-	voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128;
-	voices[voice].bender = 0;
-	voices[voice].bender_range = info->bender_range;
-
-	if (chn == 9)
-		voices[voice].fixed_pitch = 1;
-}
-
-static void guswave_bender(int dev, int voice, int value)
-{
-	int freq;
-	unsigned long   flags;
-
-	voices[voice].bender = value - 8192;
-	freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0);
-	voices[voice].current_freq = freq;
-
-	spin_lock_irqsave(&gus_lock,flags);
-	gus_select_voice(voice);
-	gus_voice_freq(freq);
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
-	int i, p, best = -1, best_time = 0x7fffffff;
-
-	p = alloc->ptr;
-	/*
-	 * First look for a completely stopped voice
-	 */
-
-	for (i = 0; i < alloc->max_voice; i++)
-	{
-		if (alloc->map[p] == 0)
-		{
-			alloc->ptr = p;
-			return p;
-		}
-		if (alloc->alloc_times[p] < best_time)
-		{
-			best = p;
-			best_time = alloc->alloc_times[p];
-		}
-		p = (p + 1) % alloc->max_voice;
-	}
-
-	/*
-	 * Then look for a releasing voice
-	 */
-
-	for (i = 0; i < alloc->max_voice; i++)
-	{
-		if (alloc->map[p] == 0xffff)
-		{
-			alloc->ptr = p;
-			return p;
-		}
-		p = (p + 1) % alloc->max_voice;
-	}
-	if (best >= 0)
-		p = best;
-
-	alloc->ptr = p;
-	return p;
-}
-
-static struct synth_operations guswave_operations =
-{
-	.owner		= THIS_MODULE,
-	.id		= "GUS",
-	.info		= &gus_info,
-	.midi_dev	= 0,
-	.synth_type	= SYNTH_TYPE_SAMPLE,
-	.synth_subtype	= SAMPLE_TYPE_GUS,
-	.open		= guswave_open,
-	.close		= guswave_close,
-	.ioctl		= guswave_ioctl,
-	.kill_note	= guswave_kill_note,
-	.start_note	= guswave_start_note,
-	.set_instr	= guswave_set_instr,
-	.reset		= guswave_reset,
-	.hw_control	= guswave_hw_control,
-	.load_patch	= guswave_load_patch,
-	.aftertouch	= guswave_aftertouch,
-	.controller	= guswave_controller,
-	.panning	= guswave_panning,
-	.volume_method	= guswave_volume_method,
-	.bender		= guswave_bender,
-	.alloc_voice	= guswave_alloc,
-	.setup_voice	= guswave_setup_voice
-};
-
-static void set_input_volumes(void)
-{
-	unsigned long flags;
-	unsigned char mask = 0xff & ~0x06;	/* Just line out enabled */
-
-	if (have_gus_max)	/* Don't disturb GUS MAX */
-		return;
-
-	spin_lock_irqsave(&gus_lock,flags);
-
-	/*
-	 *    Enable channels having vol > 10%
-	 *      Note! bit 0x01 means the line in DISABLED while 0x04 means
-	 *            the mic in ENABLED.
-	 */
-	if (gus_line_vol > 10)
-		mask &= ~0x01;
-	if (gus_mic_vol > 10)
-		mask |= 0x04;
-
-	if (recording_active)
-	{
-		/*
-		 *    Disable channel, if not selected for recording
-		 */
-		if (!(gus_recmask & SOUND_MASK_LINE))
-			mask |= 0x01;
-		if (!(gus_recmask & SOUND_MASK_MIC))
-			mask &= ~0x04;
-	}
-	mix_image &= ~0x07;
-	mix_image |= mask & 0x07;
-	outb((mix_image), u_Mixer);
-
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-#define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
-			 SOUND_MASK_SYNTH|SOUND_MASK_PCM)
-
-int gus_default_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
-	int vol, val;
-
-	if (((cmd >> 8) & 0xff) != 'M')
-		return -EINVAL;
-
-	if (!access_ok(VERIFY_WRITE, arg, sizeof(int)))
-		return -EFAULT;
-
-	if (_SIOC_DIR(cmd) & _SIOC_WRITE) 
-	{
-		if (__get_user(val, (int __user *) arg))
-			return -EFAULT;
-
-		switch (cmd & 0xff) 
-		{
-			case SOUND_MIXER_RECSRC:
-				gus_recmask = val & MIX_DEVS;
-				if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
-					gus_recmask = SOUND_MASK_MIC;
-				/* Note! Input volumes are updated during next open for recording */
-				val = gus_recmask;
-				break;
-
-			case SOUND_MIXER_MIC:
-				vol = val & 0xff;
-				if (vol < 0)
-					vol = 0;
-				if (vol > 100)
-					vol = 100;
-				gus_mic_vol = vol;
-				set_input_volumes();
-				val = vol | (vol << 8);
-				break;
-				
-			case SOUND_MIXER_LINE:
-				vol = val & 0xff;
-				if (vol < 0)
-					vol = 0;
-				if (vol > 100)
-					vol = 100;
-				gus_line_vol = vol;
-				set_input_volumes();
-				val = vol | (vol << 8);
-				break;
-
-			case SOUND_MIXER_PCM:
-				gus_pcm_volume = val & 0xff;
-				if (gus_pcm_volume < 0)
-					gus_pcm_volume = 0;
-				if (gus_pcm_volume > 100)
-					gus_pcm_volume = 100;
-				gus_audio_update_volume();
-				val = gus_pcm_volume | (gus_pcm_volume << 8);
-				break;
-
-			case SOUND_MIXER_SYNTH:
-				gus_wave_volume = val & 0xff;
-				if (gus_wave_volume < 0)
-					gus_wave_volume = 0;
-				if (gus_wave_volume > 100)
-					gus_wave_volume = 100;
-				if (active_device == GUS_DEV_WAVE) 
-				{
-					int voice;
-					for (voice = 0; voice < nr_voices; voice++)
-					dynamic_volume_change(voice);	/* Apply the new vol */
-				}
-				val = gus_wave_volume | (gus_wave_volume << 8);
-				break;
-
-			default:
-				return -EINVAL;
-		}
-	}
-	else
-	{
-		switch (cmd & 0xff) 
-		{
-			/*
-			 * Return parameters
-			 */
-			case SOUND_MIXER_RECSRC:
-				val = gus_recmask;
-				break;
-					
-			case SOUND_MIXER_DEVMASK:
-				val = MIX_DEVS;
-				break;
-
-			case SOUND_MIXER_STEREODEVS:
-				val = 0;
-				break;
-
-			case SOUND_MIXER_RECMASK:
-				val = SOUND_MASK_MIC | SOUND_MASK_LINE;
-				break;
-
-			case SOUND_MIXER_CAPS:
-				val = 0;
-				break;
-
-			case SOUND_MIXER_MIC:
-				val = gus_mic_vol | (gus_mic_vol << 8);
-				break;
-
-			case SOUND_MIXER_LINE:
-				val = gus_line_vol | (gus_line_vol << 8);
-				break;
-
-			case SOUND_MIXER_PCM:
-				val = gus_pcm_volume | (gus_pcm_volume << 8);
-				break;
-
-			case SOUND_MIXER_SYNTH:
-				val = gus_wave_volume | (gus_wave_volume << 8);
-				break;
-
-			default:
-				return -EINVAL;
-		}
-	}
-	return __put_user(val, (int __user *)arg);
-}
-
-static struct mixer_operations gus_mixer_operations =
-{
-	.owner	= THIS_MODULE,
-	.id	= "GUS",
-	.name	= "Gravis Ultrasound",
-	.ioctl	= gus_default_mixer_ioctl
-};
-
-static int __init gus_default_mixer_init(void)
-{
-	int n;
-
-	if ((n = sound_alloc_mixerdev()) != -1)
-	{	
-		/*
-		 * Don't install if there is another
-		 * mixer
-		 */
-		mixer_devs[n] = &gus_mixer_operations;
-	}
-	if (have_gus_max)
-	{
-		/*
-		 *  Enable all mixer channels on the GF1 side. Otherwise recording will
-		 *  not be possible using GUS MAX.
-		 */
-		mix_image &= ~0x07;
-		mix_image |= 0x04;	/* All channels enabled */
-		outb((mix_image), u_Mixer);
-	}
-	return n;
-}
-
-void __init gus_wave_init(struct address_info *hw_config)
-{
-	unsigned long flags;
-	unsigned char val;
-	char *model_num = "2.4";
-	char tmp[64];
-	int gus_type = 0x24;	/* 2.4 */
-
-	int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
-	int sdev;
-
-	hw_config->slots[0] = -1;	/* No wave */
-	hw_config->slots[1] = -1;	/* No ad1848 */
-	hw_config->slots[4] = -1;	/* No audio */
-	hw_config->slots[5] = -1;	/* No mixer */
-
-	if (!gus_pnp_flag)
-	{
-		if (irq < 0 || irq > 15)
-		{
-			printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq);
-			return;
-		}
-	}
-	
-	if (dma < 0 || dma > 7 || dma == 4)
-	{
-		printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma);
-		return;
-	}
-	gus_irq = irq;
-	gus_dma = dma;
-	gus_dma2 = dma2;
-	gus_hw_config = hw_config;
-
-	if (gus_dma2 == -1)
-		gus_dma2 = dma;
-
-	/*
-	 * Try to identify the GUS model.
-	 *
-	 *  Versions < 3.6 don't have the digital ASIC. Try to probe it first.
-	 */
-
-	spin_lock_irqsave(&gus_lock,flags);
-	outb((0x20), gus_base + 0x0f);
-	val = inb(gus_base + 0x0f);
-	spin_unlock_irqrestore(&gus_lock,flags);
-
-	if (gus_pnp_flag || (val != 0xff && (val & 0x06)))	/* Should be 0x02?? */
-	{
-		int             ad_flags = 0;
-
-		if (gus_pnp_flag)
-			ad_flags = 0x12345678;	/* Interwave "magic" */
-		/*
-		 * It has the digital ASIC so the card is at least v3.4.
-		 * Next try to detect the true model.
-		 */
-
-		if (gus_pnp_flag)	/* Hack hack hack */
-			val = 10;
-		else
-			val = inb(u_MixSelect);
-
-		/*
-		 * Value 255 means pre-3.7 which don't have mixer.
-		 * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
-		 * 10 and above is GUS MAX which has the CS4231 codec/mixer.
-		 *
-		 */
-
-		if (val == 255 || val < 5)
-		{
-			model_num = "3.4";
-			gus_type = 0x34;
-		}
-		else if (val < 10)
-		{
-			model_num = "3.7";
-			gus_type = 0x37;
-			mixer_type = ICS2101;
-			request_region(u_MixSelect, 1, "GUS mixer");
-		}
-		else
-		{
-			struct resource *ports;
-			ports = request_region(gus_base + 0x10c, 4, "ad1848");
-			model_num = "MAX";
-			gus_type = 0x40;
-			mixer_type = CS4231;
-#ifdef CONFIG_SOUND_GUSMAX
-			{
-				unsigned char   max_config = 0x40;	/* Codec enable */
-
-				if (gus_dma2 == -1)
-					gus_dma2 = gus_dma;
-
-				if (gus_dma > 3)
-					max_config |= 0x10;		/* 16 bit capture DMA */
-
-				if (gus_dma2 > 3)
-					max_config |= 0x20;		/* 16 bit playback DMA */
-
-				max_config |= (gus_base >> 4) & 0x0f;	/* Extract the X from 2X0 */
-
-				outb((max_config), gus_base + 0x106);	/* UltraMax control */
-			}
-
-			if (!ports)
-				goto no_cs4231;
-
-			if (ad1848_detect(ports, &ad_flags, hw_config->osp))
-			{
-				char           *name = "GUS MAX";
-				int             old_num_mixers = num_mixers;
-
-				if (gus_pnp_flag)
-					name = "GUS PnP";
-
-				gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
-				gus_wave_volume = 90;
-				have_gus_max = 1;
-				if (hw_config->name)
-					name = hw_config->name;
-
-				hw_config->slots[1] = ad1848_init(name, ports,
-							-irq, gus_dma2,	/* Playback DMA */
-							gus_dma,	/* Capture DMA */
-							1,		/* Share DMA channels with GF1 */
-							hw_config->osp,
-							THIS_MODULE);
-
-				if (num_mixers > old_num_mixers)
-				{
-					/* GUS has it's own mixer map */
-					AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
-					AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
-					AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
-				}
-			}
-			else {
-				release_region(gus_base + 0x10c, 4);
-			no_cs4231:
-				printk(KERN_WARNING "GUS: No CS4231 ??");
-			}
-#else
-			printk(KERN_ERR "GUS MAX found, but not compiled in\n");
-#endif
-		}
-	}
-	else
-	{
-		/*
-		 * ASIC not detected so the card must be 2.2 or 2.4.
-		 * There could still be the 16-bit/mixer daughter card.
-		 */
-	}
-
-	if (hw_config->name)
-		snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name,
-			 (int) gus_mem_size / 1024);
-	else if (gus_pnp_flag)
-		snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)",
-			 (int) gus_mem_size / 1024);
-	else
-		snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num,
-			 (int) gus_mem_size / 1024);
-
-
-	samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples));
-	if (samples == NULL)
-	{
-		printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
-		return;
-	}
-	conf_printf(tmp, hw_config);
-	strlcpy(gus_info.name, tmp, sizeof(gus_info.name));
-
-	if ((sdev = sound_alloc_synthdev()) == -1)
-		printk(KERN_WARNING "gus_init: Too many synthesizers\n");
-	else
-	{
-		voice_alloc = &guswave_operations.alloc;
-		if (iw_mode)
-			guswave_operations.id = "IWAVE";
-		hw_config->slots[0] = sdev;
-		synth_devs[sdev] = &guswave_operations;
-		sequencer_init();
-		gus_tmr_install(gus_base + 8);
-	}
-
-	reset_sample_memory();
-
-	gus_initialize();
-	
-	if ((gus_mem_size > 0) && !gus_no_wave_dma)
-	{
-		hw_config->slots[4] = -1;
-		if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
-					"Ultrasound",
-					&gus_audio_driver,
-					sizeof(struct audio_driver),
-					NEEDS_RESTART |
-		                   	((!iw_mode && dma2 != dma && dma2 != -1) ?
-						DMA_DUPLEX : 0),
-					AFMT_U8 | AFMT_S16_LE,
-					NULL, dma, dma2)) < 0)
-		{
-			return;
-		}
-
-		hw_config->slots[4] = gus_devnum;
-		audio_devs[gus_devnum]->min_fragment = 9;	/* 512k */
-		audio_devs[gus_devnum]->max_fragment = 11;	/* 8k (must match size of bounce_buf */
-		audio_devs[gus_devnum]->mixer_dev = -1;	/* Next mixer# */
-		audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
-	}
-	
-	/*
-	 *  Mixer dependent initialization.
-	 */
-
-	switch (mixer_type)
-	{
-		case ICS2101:
-			gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
-			gus_wave_volume = 90;
-			request_region(u_MixSelect, 1, "GUS mixer");
-			hw_config->slots[5] = ics2101_mixer_init();
-			audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];	/* Next mixer# */
-			return;
-
-		case CS4231:
-			/* Initialized elsewhere (ad1848.c) */
-		default:
-			hw_config->slots[5] = gus_default_mixer_init();
-			audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5];	/* Next mixer# */
-			return;
-	}
-}
-
-void __exit gus_wave_unload(struct address_info *hw_config)
-{
-#ifdef CONFIG_SOUND_GUSMAX
-	if (have_gus_max)
-	{
-		ad1848_unload(gus_base + 0x10c,
-				-gus_irq,
-				gus_dma2,	/* Playback DMA */
-				gus_dma,	/* Capture DMA */
-				1);	/* Share DMA channels with GF1 */
-	}
-#endif
-
-	if (mixer_type == ICS2101)
-	{
-		release_region(u_MixSelect, 1);
-	}
-	if (hw_config->slots[0] != -1)
-		sound_unload_synthdev(hw_config->slots[0]);
-	if (hw_config->slots[1] != -1)
-		sound_unload_audiodev(hw_config->slots[1]);
-	if (hw_config->slots[2] != -1)
-		sound_unload_mididev(hw_config->slots[2]);
-	if (hw_config->slots[4] != -1)
-		sound_unload_audiodev(hw_config->slots[4]);
-	if (hw_config->slots[5] != -1)
-		sound_unload_mixerdev(hw_config->slots[5]);
-	
-	vfree(samples);
-	samples=NULL;
-}
-/* called in interrupt context */
-static void do_loop_irq(int voice)
-{
-	unsigned char   tmp;
-	int             mode, parm;
-
-	spin_lock(&gus_lock);
-	gus_select_voice(voice);
-
-	tmp = gus_read8(0x00);
-	tmp &= ~0x20;		/*
-				 * Disable wave IRQ for this_one voice
-				 */
-	gus_write8(0x00, tmp);
-
-	if (tmp & 0x03)		/* Voice stopped */
-		voice_alloc->map[voice] = 0;
-
-	mode = voices[voice].loop_irq_mode;
-	voices[voice].loop_irq_mode = 0;
-	parm = voices[voice].loop_irq_parm;
-
-	switch (mode)
-	{
-		case LMODE_FINISH:	/*
-					 * Final loop finished, shoot volume down
-					 */
-
-			if ((int) (gus_read16(0x09) >> 4) < 100)	/*
-									 * Get current volume
-									 */
-			{
-				gus_voice_off();
-				gus_rampoff();
-				gus_voice_init(voice);
-				break;
-			}
-			gus_ramp_range(65, 4065);
-			gus_ramp_rate(0, 63);		/*
-							 * Fastest possible rate
-							 */
-			gus_rampon(0x20 | 0x40);	/*
-							 * Ramp down, once, irq
-							 */
-			voices[voice].volume_irq_mode = VMODE_HALT;
-			break;
-
-		case LMODE_PCM_STOP:
-			pcm_active = 0;	/* Signal to the play_next_pcm_block routine */
-		case LMODE_PCM:
-		{
-			pcm_qlen--;
-			pcm_head = (pcm_head + 1) % pcm_nblk;
-			if (pcm_qlen && pcm_active)
-			{
-				play_next_pcm_block();
-			}
-			else
-			{
-				/* Underrun. Just stop the voice */
-				gus_select_voice(0);	/* Left channel */
-				gus_voice_off();
-				gus_rampoff();
-				gus_select_voice(1);	/* Right channel */
-				gus_voice_off();
-				gus_rampoff();
-				pcm_active = 0;
-			}
-
-			/*
-			 * If the queue was full before this interrupt, the DMA transfer was
-			 * suspended. Let it continue now.
-			 */
-			
-			if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
-				DMAbuf_outputintr(gus_devnum, 0);
-		}
-		break;
-
-		default:
-			break;
-	}
-	spin_unlock(&gus_lock);
-}
-
-static void do_volume_irq(int voice)
-{
-	unsigned char tmp;
-	int mode, parm;
-	unsigned long flags;
-
-	spin_lock_irqsave(&gus_lock,flags);
-
-	gus_select_voice(voice);
-	tmp = gus_read8(0x0d);
-	tmp &= ~0x20;		/*
-				 * Disable volume ramp IRQ
-				 */
-	gus_write8(0x0d, tmp);
-
-	mode = voices[voice].volume_irq_mode;
-	voices[voice].volume_irq_mode = 0;
-	parm = voices[voice].volume_irq_parm;
-
-	switch (mode)
-	{
-		case VMODE_HALT:	/* Decay phase finished */
-			if (iw_mode)
-				gus_write8(0x15, 0x02);	/* Set voice deactivate bit of SMSI */
-			spin_unlock_irqrestore(&gus_lock,flags);
-			gus_voice_init(voice);
-			break;
-
-		case VMODE_ENVELOPE:
-			gus_rampoff();
-			spin_unlock_irqrestore(&gus_lock,flags);
-			step_envelope(voice);
-			break;
-
-		case VMODE_START_NOTE:
-			spin_unlock_irqrestore(&gus_lock,flags);
-			guswave_start_note2(voices[voice].dev_pending, voice,
-				      voices[voice].note_pending, voices[voice].volume_pending);
-			if (voices[voice].kill_pending)
-				guswave_kill_note(voices[voice].dev_pending, voice,
-					  voices[voice].note_pending, 0);
-
-			if (voices[voice].sample_pending >= 0)
-			{
-				guswave_set_instr(voices[voice].dev_pending, voice,
-					voices[voice].sample_pending);
-				voices[voice].sample_pending = -1;
-			}
-			break;
-
-		default:
-			spin_unlock_irqrestore(&gus_lock,flags);
-	}
-}
-/* called in irq context */
-void gus_voice_irq(void)
-{
-	unsigned long wave_ignore = 0, volume_ignore = 0;
-	unsigned long voice_bit;
-
-	unsigned char src, voice;
-
-	while (1)
-	{
-		src = gus_read8(0x0f);	/*
-					 * Get source info
-					 */
-		voice = src & 0x1f;
-		src &= 0xc0;
-
-		if (src == (0x80 | 0x40))
-			return;	/*
-				 * No interrupt
-				 */
-
-		voice_bit = 1 << voice;
-
-		if (!(src & 0x80))	/*
-					 * Wave IRQ pending
-					 */
-			if (!(wave_ignore & voice_bit) && (int) voice < nr_voices)	/*
-											 * Not done
-											 * yet
-											 */
-			{
-				wave_ignore |= voice_bit;
-				do_loop_irq(voice);
-			}
-		if (!(src & 0x40))	/*
-					 * Volume IRQ pending
-					 */
-			if (!(volume_ignore & voice_bit) && (int) voice < nr_voices)	/*
-											   * Not done
-											   * yet
-											 */
-			{
-				volume_ignore |= voice_bit;
-				do_volume_irq(voice);
-			}
-	}
-}
-
-void guswave_dma_irq(void)
-{
-	unsigned char   status;
-
-	status = gus_look8(0x41);	/* Get DMA IRQ Status */
-	if (status & 0x40)	/* DMA interrupt pending */
-		switch (active_device)
-		{
-			case GUS_DEV_WAVE:
-				wake_up(&dram_sleeper);
-				break;
-
-			case GUS_DEV_PCM_CONTINUE:	/* Left channel data transferred */
-				gus_write8(0x41, 0);	/* Disable GF1 DMA */
-				gus_transfer_output_block(pcm_current_dev, pcm_current_buf,
-						pcm_current_count,
-						pcm_current_intrflag, 1);
-				break;
-
-			case GUS_DEV_PCM_DONE:	/* Right or mono channel data transferred */
-				gus_write8(0x41, 0);	/* Disable GF1 DMA */
-				if (pcm_qlen < pcm_nblk)
-				{
-					dma_active = 0;
-					if (gus_busy)
-					{
-						if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
-							DMAbuf_outputintr(gus_devnum, 0);
-					}
-				}
-				break;
-
-			default:
-				break;
-	}
-	status = gus_look8(0x49);	/*
-					 * Get Sampling IRQ Status
-					 */
-	if (status & 0x40)	/*
-				 * Sampling Irq pending
-				 */
-	{
-		DMAbuf_inputintr(gus_devnum);
-	}
-}
-
-/*
- * Timer stuff
- */
-
-static volatile int select_addr, data_addr;
-static volatile int curr_timer;
-
-void gus_timer_command(unsigned int addr, unsigned int val)
-{
-	int i;
-
-	outb(((unsigned char) (addr & 0xff)), select_addr);
-
-	for (i = 0; i < 2; i++)
-		inb(select_addr);
-
-	outb(((unsigned char) (val & 0xff)), data_addr);
-
-	for (i = 0; i < 2; i++)
-		inb(select_addr);
-}
-
-static void arm_timer(int timer, unsigned int interval)
-{
-	curr_timer = timer;
-
-	if (timer == 1)
-	{
-		gus_write8(0x46, 256 - interval);	/* Set counter for timer 1 */
-		gus_write8(0x45, 0x04);			/* Enable timer 1 IRQ */
-		gus_timer_command(0x04, 0x01);		/* Start timer 1 */
-	}
-	else
-	{
-		gus_write8(0x47, 256 - interval);	/* Set counter for timer 2 */
-		gus_write8(0x45, 0x08);			/* Enable timer 2 IRQ */
-		gus_timer_command(0x04, 0x02);		/* Start timer 2 */
-	}
-
-	gus_timer_enabled = 1;
-}
-
-static unsigned int gus_tmr_start(int dev, unsigned int usecs_per_tick)
-{
-	int timer_no, resolution;
-	int divisor;
-
-	if (usecs_per_tick > (256 * 80))
-	{
-		timer_no = 2;
-		resolution = 320;	/* usec */
-	}
-	else
-	{
-		timer_no = 1;
-		resolution = 80;	/* usec */
-	}
-	divisor = (usecs_per_tick + (resolution / 2)) / resolution;
-	arm_timer(timer_no, divisor);
-
-	return divisor * resolution;
-}
-
-static void gus_tmr_disable(int dev)
-{
-	gus_write8(0x45, 0);	/* Disable both timers */
-	gus_timer_enabled = 0;
-}
-
-static void gus_tmr_restart(int dev)
-{
-	if (curr_timer == 1)
-		gus_write8(0x45, 0x04);		/* Start timer 1 again */
-	else
-		gus_write8(0x45, 0x08);		/* Start timer 2 again */
-	gus_timer_enabled = 1;
-}
-
-static struct sound_lowlev_timer gus_tmr =
-{
-	0,
-	1,
-	gus_tmr_start,
-	gus_tmr_disable,
-	gus_tmr_restart
-};
-
-static void gus_tmr_install(int io_base)
-{
-	struct sound_lowlev_timer *tmr;
-
-	select_addr = io_base;
-	data_addr = io_base + 1;
-
-	tmr = &gus_tmr;
-
-#ifdef THIS_GETS_FIXED
-	sound_timer_init(&gus_tmr, "GUS");
-#endif
-}
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
deleted file mode 100644
index 6601b28..0000000
--- a/sound/oss/harmony.c
+++ /dev/null
@@ -1,1330 +0,0 @@
-/*
- 	sound/oss/harmony.c
-
-	This is a sound driver for ASP's and Lasi's Harmony sound chip
-	and is unlikely to be used for anything other than on a HP PA-RISC.
-
-	Harmony is found in HP 712s, 715/new and many other GSC based machines.
-	On older 715 machines you'll find the technically identical chip 
-	called 'Vivace'. Both Harmony and Vicace are supported by this driver.
-
-	Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@onefishtwo.ca>
-	Copyright 2000-2003 (c) Helge Deller <deller@gmx.de>
-	Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr>
-	Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr>
-	Copyright 2004 (c) Stuart Brady <sdbrady@ntlworld.com>
-
-				
-TODO:
-	- fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to
-		return the real values
-	- add private ioctl for selecting line- or microphone input
-		(only one of them is available at the same time)
-	- add module parameters
-	- implement mmap functionality
-	- implement gain meter ?
-	- ...
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-
-#include <asm/parisc-device.h>
-#include <asm/io.h>
-
-#include "sound_config.h"
-
-
-#define PFX "harmony: "
-#define HARMONY_VERSION "V0.9a"
-
-#undef DEBUG
-#ifdef DEBUG
-# define DPRINTK printk 
-#else
-# define DPRINTK(x,...)
-#endif
-
-
-#define MAX_BUFS 10		/* maximum number of rotating buffers */
-#define HARMONY_BUF_SIZE 4096	/* needs to be a multiple of PAGE_SIZE (4096)! */
-
-#define CNTL_C		0x80000000
-#define	CNTL_ST		0x00000020
-#define CNTL_44100	0x00000015	/* HARMONY_SR_44KHZ */
-#define CNTL_8000	0x00000008	/* HARMONY_SR_8KHZ */
-
-#define GAINCTL_HE	0x08000000
-#define GAINCTL_LE	0x04000000
-#define GAINCTL_SE	0x02000000
-
-#define DSTATUS_PN	0x00000200
-#define DSTATUS_RN	0x00000002
-
-#define DSTATUS_IE	0x80000000
-
-#define HARMONY_DF_16BIT_LINEAR	0
-#define HARMONY_DF_8BIT_ULAW	1
-#define HARMONY_DF_8BIT_ALAW	2
-
-#define HARMONY_SS_MONO		0
-#define HARMONY_SS_STEREO	1
-
-#define HARMONY_SR_8KHZ		0x08
-#define HARMONY_SR_16KHZ	0x09
-#define HARMONY_SR_27KHZ	0x0A
-#define HARMONY_SR_32KHZ	0x0B
-#define HARMONY_SR_48KHZ	0x0E
-#define HARMONY_SR_9KHZ		0x0F
-#define HARMONY_SR_5KHZ		0x10
-#define HARMONY_SR_11KHZ	0x11
-#define HARMONY_SR_18KHZ	0x12
-#define HARMONY_SR_22KHZ	0x13
-#define HARMONY_SR_37KHZ	0x14
-#define HARMONY_SR_44KHZ	0x15
-#define HARMONY_SR_33KHZ	0x16
-#define HARMONY_SR_6KHZ		0x17
-
-/*
- * Some magics numbers used to auto-detect file formats
- */
-
-#define HARMONY_MAGIC_8B_ULAW	1
-#define HARMONY_MAGIC_8B_ALAW	27
-#define HARMONY_MAGIC_16B_LINEAR 3
-#define HARMONY_MAGIC_MONO	1
-#define HARMONY_MAGIC_STEREO	2
-
-/*
- * Channels Positions in mixer register
- */
-
-#define GAIN_HE_SHIFT   27
-#define GAIN_HE_MASK    ( 1 << GAIN_HE_SHIFT) 
-#define GAIN_LE_SHIFT   26
-#define GAIN_LE_MASK    ( 1 << GAIN_LE_SHIFT) 
-#define GAIN_SE_SHIFT   25
-#define GAIN_SE_MASK    ( 1 << GAIN_SE_SHIFT) 
-#define GAIN_IS_SHIFT   24
-#define GAIN_IS_MASK    ( 1 << GAIN_IS_SHIFT) 
-#define GAIN_MA_SHIFT   20
-#define GAIN_MA_MASK    ( 0x0f << GAIN_MA_SHIFT) 
-#define GAIN_LI_SHIFT   16
-#define GAIN_LI_MASK    ( 0x0f << GAIN_LI_SHIFT) 
-#define GAIN_RI_SHIFT   12
-#define GAIN_RI_MASK    ( 0x0f << GAIN_RI_SHIFT) 
-#define GAIN_LO_SHIFT   6
-#define GAIN_LO_MASK    ( 0x3f << GAIN_LO_SHIFT) 
-#define GAIN_RO_SHIFT   0
-#define GAIN_RO_MASK    ( 0x3f << GAIN_RO_SHIFT) 
-
-
-#define MAX_OUTPUT_LEVEL  (GAIN_RO_MASK >> GAIN_RO_SHIFT)
-#define MAX_INPUT_LEVEL   (GAIN_RI_MASK >> GAIN_RI_SHIFT)
-#define MAX_MONITOR_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT)
-
-#define MIXER_INTERNAL   SOUND_MIXER_LINE1
-#define MIXER_LINEOUT    SOUND_MIXER_LINE2
-#define MIXER_HEADPHONES SOUND_MIXER_LINE3
-
-#define MASK_INTERNAL   SOUND_MASK_LINE1
-#define MASK_LINEOUT    SOUND_MASK_LINE2
-#define MASK_HEADPHONES SOUND_MASK_LINE3
-
-/*
- * Channels Mask in mixer register
- */
-
-#define GAIN_TOTAL_SILENCE 0x00F00FFF
-#define GAIN_DEFAULT       0x0FF00000
-
-
-struct harmony_hpa {
-	u8	unused000;
-	u8	id;
-	u8	teleshare_id;
-	u8	unused003;
-	u32	reset;
-	u32	cntl;
-	u32	gainctl;
-	u32	pnxtadd;
-	u32	pcuradd;
-	u32	rnxtadd;
-	u32	rcuradd;
-	u32	dstatus;
-	u32	ov;
-	u32	pio;
-	u32	unused02c;
-	u32	unused030[3];
-	u32	diag;
-};
-
-struct harmony_dev {
-	struct harmony_hpa *hpa;
-	struct parisc_device *dev;
-	u32 current_gain;
-	u32 dac_rate;		/* 8000 ... 48000 (Hz) */
-	u8 data_format;		/* HARMONY_DF_xx_BIT_xxx */
-	u8 sample_rate;		/* HARMONY_SR_xx_KHZ */
-	u8 stereo_select;	/* HARMONY_SS_MONO or HARMONY_SS_STEREO */
-	int format_initialized  :1;
-	int suspended_playing   :1;
-	int suspended_recording :1;
-	
-	int blocked_playing     :1;
-	int blocked_recording   :1;
-	int audio_open		:1;
-	int mixer_open		:1;
-	
-	wait_queue_head_t wq_play, wq_record;
-	int first_filled_play;	/* first buffer containing data (next to play) */
-	int nb_filled_play; 
-	int play_offset;
-	int first_filled_record;
-	int nb_filled_record;
-		
-	int dsp_unit, mixer_unit;
-};
-
-
-static struct harmony_dev harmony;
-
-
-/*
- * Dynamic sound buffer allocation and DMA memory
- */
-
-struct harmony_buffer {
-	unsigned char *addr;
-	dma_addr_t dma_handle;
-	int dma_coherent;	/* Zero if dma_alloc_coherent() fails */
-	unsigned int len;
-};
-
-/*
- * Harmony memory buffers
- */
-
-static struct harmony_buffer played_buf, recorded_buf, silent, graveyard;
-
-
-#define CHECK_WBACK_INV_OFFSET(b,offset,len) \
-        do { if (!b.dma_coherent) \
-		dma_cache_wback_inv((unsigned long)b.addr+offset,len); \
-	} while (0) 
-
-	
-static int __init harmony_alloc_buffer(struct harmony_buffer *b, 
-		unsigned int buffer_count)
-{
-	b->len = buffer_count * HARMONY_BUF_SIZE;
-	b->addr = dma_alloc_coherent(&harmony.dev->dev, 
-			  b->len, &b->dma_handle, GFP_KERNEL|GFP_DMA);
-	if (b->addr && b->dma_handle) {
-		b->dma_coherent = 1;
-		DPRINTK(KERN_INFO PFX "coherent memory: 0x%lx, played_buf: 0x%lx\n",
-				(unsigned long)b->dma_handle, (unsigned long)b->addr);
-	} else {
-		b->dma_coherent = 0;
-		/* kmalloc()ed memory will HPMC on ccio machines ! */
-		b->addr = kmalloc(b->len, GFP_KERNEL);
-		if (!b->addr) {
-			printk(KERN_ERR PFX "couldn't allocate memory\n");
-			return -EBUSY;
-		}
-		b->dma_handle = __pa(b->addr);
-	}
-	return 0;
-}
-
-static void __exit harmony_free_buffer(struct harmony_buffer *b)
-{
-	if (!b->addr)
-		return;
-
-	if (b->dma_coherent)
-		dma_free_coherent(&harmony.dev->dev,
-				b->len, b->addr, b->dma_handle);
-	else
-		kfree(b->addr);
-
-	memset(b, 0, sizeof(*b));
-}
-
-
-
-/*
- * Low-Level sound-chip programming
- */
-
-static void __inline__ harmony_wait_CNTL(void)
-{
-	/* Wait until we're out of control mode */
-	while (gsc_readl(&harmony.hpa->cntl) & CNTL_C)
-		/* wait */ ;
-}
-
-
-static void harmony_update_control(void) 
-{
-	u32 default_cntl;
-	
-	/* Set CNTL */
-	default_cntl = (CNTL_C |  		/* The C bit */
-		(harmony.data_format << 6) |	/* Set the data format */
-		(harmony.stereo_select << 5) |	/* Stereo select */
-		(harmony.sample_rate));		/* Set sample rate */
-	harmony.format_initialized = 1;
-	
-	/* initialize CNTL */
-	gsc_writel(default_cntl, &harmony.hpa->cntl);
-}
-
-static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select) 
-{
-	harmony.sample_rate = sample_rate;
-	harmony.data_format = data_format;
-	harmony.stereo_select = stereo_select;
-	harmony_update_control();
-}
-
-static void harmony_set_rate(u8 data_rate) 
-{
-	harmony.sample_rate = data_rate;
-	harmony_update_control();
-}
-
-static int harmony_detect_rate(int *freq)
-{
-	int newrate;
-	switch (*freq) {
-	case 8000:	newrate = HARMONY_SR_8KHZ;	break;
-	case 16000:	newrate = HARMONY_SR_16KHZ;	break; 
-	case 27428:	newrate = HARMONY_SR_27KHZ;	break; 
-	case 32000:	newrate = HARMONY_SR_32KHZ;	break; 
-	case 48000:	newrate = HARMONY_SR_48KHZ;	break; 
-	case 9600:	newrate = HARMONY_SR_9KHZ;	break; 
-	case 5512:	newrate = HARMONY_SR_5KHZ;	break; 
-	case 11025:	newrate = HARMONY_SR_11KHZ;	break; 
-	case 18900:	newrate = HARMONY_SR_18KHZ;	break; 
-	case 22050:	newrate = HARMONY_SR_22KHZ;	break; 
-	case 37800:	newrate = HARMONY_SR_37KHZ;	break; 
-	case 44100:	newrate = HARMONY_SR_44KHZ;	break; 
-	case 33075:	newrate = HARMONY_SR_33KHZ;	break; 
-	case 6615:	newrate = HARMONY_SR_6KHZ;	break; 
-	default:	newrate = HARMONY_SR_8KHZ; 
-			*freq = 8000;			break;
-	}
-	return newrate;
-}
-
-static void harmony_set_format(u8 data_format) 
-{
-	harmony.data_format = data_format;
-	harmony_update_control();
-}
-
-static void harmony_set_stereo(u8 stereo_select) 
-{
-	harmony.stereo_select = stereo_select;
-	harmony_update_control();
-}
-
-static void harmony_disable_interrupts(void) 
-{
-	harmony_wait_CNTL();
-	gsc_writel(0, &harmony.hpa->dstatus); 
-}
-
-static void harmony_enable_interrupts(void) 
-{
-	harmony_wait_CNTL();
-	gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus); 
-}
-
-/*
- * harmony_silence()
- *
- * This subroutine fills in a buffer starting at location start and
- * silences for length bytes.  This references the current
- * configuration of the audio format.
- *
- */
-
-static void harmony_silence(struct harmony_buffer *buffer, int start, int length) 
-{
-	u8 silence_char;
-
-	/* Despite what you hear, silence is different in
-	   different audio formats.  */
-	switch (harmony.data_format) {
-		case HARMONY_DF_8BIT_ULAW:	silence_char = 0x55; break;
-		case HARMONY_DF_8BIT_ALAW:	silence_char = 0xff; break;
-		case HARMONY_DF_16BIT_LINEAR:	/* fall through */
-		default:			silence_char = 0;
-	}
-
-	memset(buffer->addr+start, silence_char, length);
-}
-
-
-static int harmony_audio_open(struct inode *inode, struct file *file)
-{
-	if (harmony.audio_open) 
-		return -EBUSY;
-	
-	harmony.audio_open = 1;
-	harmony.suspended_playing = harmony.suspended_recording = 1;
-	harmony.blocked_playing   = harmony.blocked_recording   = 0;
-	harmony.first_filled_play = harmony.first_filled_record = 0;
-	harmony.nb_filled_play    = harmony.nb_filled_record    = 0;
-	harmony.play_offset = 0;
-	init_waitqueue_head(&harmony.wq_play);
-	init_waitqueue_head(&harmony.wq_record);
-	
-	/* Start off in a balanced mode. */
-	harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
-	harmony_update_control();
-	harmony.format_initialized = 0;
-
-	/* Clear out all the buffers and flush to cache */
-	harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-	CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-	
-	return 0;
-}
-
-/*
- * Release (close) the audio device.
- */
-
-static int harmony_audio_release(struct inode *inode, struct file *file)
-{
-	if (!harmony.audio_open) 
-		return -EBUSY;
-	
-	harmony.audio_open = 0;
-
-	return 0;
-}
-
-/*
- * Read recorded data off the audio device.
- */
-
-static ssize_t harmony_audio_read(struct file *file,
-                                char *buffer,
-                                size_t size_count,
-                                loff_t *ppos)
-{
-	int total_count = (int) size_count;
-	int count = 0;
-	int buf_to_read;
-
-	while (count<total_count) {
-		/* Wait until we're out of control mode */
-		harmony_wait_CNTL();
-		
-		/* Figure out which buffer to fill in */
-		if (harmony.nb_filled_record <= 2) {
-			harmony.blocked_recording = 1;
-		        if (harmony.suspended_recording) {
-				harmony.suspended_recording = 0;
-				harmony_enable_interrupts();
-			}
-							
-			interruptible_sleep_on(&harmony.wq_record);
-			harmony.blocked_recording = 0;
-		}
-		
-		if (harmony.nb_filled_record < 2)
-			return -EBUSY;
-		
-		buf_to_read = harmony.first_filled_record;
-
-		/* Copy the page to an aligned buffer */
-		if (copy_to_user(buffer+count, recorded_buf.addr +
-				 (HARMONY_BUF_SIZE*buf_to_read),
-				 HARMONY_BUF_SIZE)) {
-			count = -EFAULT;
-			break;
-		}
-		
-		harmony.nb_filled_record--;
-		harmony.first_filled_record++;
-		harmony.first_filled_record %= MAX_BUFS;
-				
-		count += HARMONY_BUF_SIZE;
-	}
-	return count;
-}
-
-
-
-
-/*
- * Here is the place where we try to recognize file format.
- * Sun/NeXT .au files begin with the string .snd
- * At offset 12 is specified the encoding.
- * At offset 16 is specified speed rate
- * At Offset 20 is specified the numbers of voices
- */
-
-#define four_bytes_to_u32(start) (file_header[start] << 24)|\
-                                  (file_header[start+1] << 16)|\
-                                  (file_header[start+2] << 8)|\
-                                  (file_header[start+3]);
-
-#define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\
-                                                    
-
-static int harmony_format_auto_detect(const char *buffer, int block_size)
-{
-	u8 file_header[24];
-	u32 start_string;
-	int ret = 0;
-	
-	if (block_size>24) {
-		if (copy_from_user(file_header, buffer, sizeof(file_header)))
-			ret = -EFAULT;
-			
-		start_string = four_bytes_to_u32(0);
-		
-		if ((file_header[4]==0) && (start_string==0x2E736E64)) {
-			u32 format;
-			u32 nb_voices;
-			u32 speed;
-			
-			format = four_bytes_to_u32(12);
-			nb_voices = four_bytes_to_u32(20);
-			speed = four_bytes_to_u32(16);
-			
-			switch (format) {
-			case HARMONY_MAGIC_8B_ULAW:
-				harmony.data_format = HARMONY_DF_8BIT_ULAW;
-				break;
-			case HARMONY_MAGIC_8B_ALAW:
-				harmony.data_format = HARMONY_DF_8BIT_ALAW;
-				break;
-			case HARMONY_MAGIC_16B_LINEAR:
-				harmony.data_format = HARMONY_DF_16BIT_LINEAR;
-				break;
-			default:
-				harmony_set_control(HARMONY_DF_16BIT_LINEAR,
-						HARMONY_SR_44KHZ, HARMONY_SS_STEREO);
-				goto out;
-			}
-			switch (nb_voices) {
-			case HARMONY_MAGIC_MONO:
-				harmony.stereo_select = HARMONY_SS_MONO;
-				break;
-			case HARMONY_MAGIC_STEREO:
-				harmony.stereo_select = HARMONY_SS_STEREO;
-				break;
-			default:
-				harmony.stereo_select = HARMONY_SS_MONO;
-				break;
-			}
-			harmony_set_rate(harmony_detect_rate(&speed));
-			harmony.dac_rate = speed;
-			goto out;
-		}
-	}
-	harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
-out:
-	return ret;
-}
-#undef four_bytes_to_u32
-
-
-static ssize_t harmony_audio_write(struct file *file,
-                                 const char *buffer,
-                                 size_t size_count,
-                                 loff_t *ppos)
-{
-	int total_count = (int) size_count;
-	int count = 0;
-	int frame_size;
-	int buf_to_fill;
-	int fresh_buffer;
-
-	if (!harmony.format_initialized) {
-		if (harmony_format_auto_detect(buffer, total_count))
-			return -EFAULT;
-	}
-	
-	while (count<total_count) {
-		/* Wait until we're out of control mode */
-		harmony_wait_CNTL();
-
-		/* Figure out which buffer to fill in */
-		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) {
-			harmony.blocked_playing = 1;
-			interruptible_sleep_on(&harmony.wq_play);
-			harmony.blocked_playing = 0;
-		}
-		if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset)
-			return -EBUSY;
-		
-		
-		buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play); 
-		if (harmony.play_offset) {
-			buf_to_fill--;
-			buf_to_fill += MAX_BUFS;
-		}
-		buf_to_fill %= MAX_BUFS;
-		
-		fresh_buffer = (harmony.play_offset == 0);
-		
-		/* Figure out the size of the frame */
-		if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) {
-			frame_size = HARMONY_BUF_SIZE - harmony.play_offset;
-		} else {
-			frame_size = total_count - count;
-			/* Clear out the buffer, since there we'll only be 
-			   overlaying part of the old buffer with the new one */
-			harmony_silence(&played_buf, 
-				HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset,
-				HARMONY_BUF_SIZE-frame_size-harmony.play_offset);
-		}
-
-		/* Copy the page to an aligned buffer */
-		if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset, 
-				   buffer+count, frame_size))
-			return -EFAULT;
-		CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset), 
-				frame_size);
-	
-		if (fresh_buffer)
-			harmony.nb_filled_play++;
-		
-		count += frame_size;
-		harmony.play_offset += frame_size;
-		harmony.play_offset %= HARMONY_BUF_SIZE;
-		if (harmony.suspended_playing && (harmony.nb_filled_play>=4))
-			harmony_enable_interrupts();
-	}
-	
-	return count;
-}
-
-static unsigned int harmony_audio_poll(struct file *file,
-                                     struct poll_table_struct *wait)
-{
-	unsigned int mask = 0;
-	
-	if (file->f_mode & FMODE_READ) {
-		if (!harmony.suspended_recording)
-			poll_wait(file, &harmony.wq_record, wait);
-		if (harmony.nb_filled_record)
-			mask |= POLLIN | POLLRDNORM;
-	}
-
-	if (file->f_mode & FMODE_WRITE) {
-		if (!harmony.suspended_playing)
-			poll_wait(file, &harmony.wq_play, wait);
-		if (harmony.nb_filled_play)
-			mask |= POLLOUT | POLLWRNORM;
-	}
-
-	return mask;
-}
-
-static int harmony_audio_ioctl(struct inode *inode,
-                                struct file *file,
-				unsigned int cmd,
-                                unsigned long arg)
-{
-	int ival, new_format;
-	int frag_size, frag_buf;
-	struct audio_buf_info info;
-	
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, (int *) arg);
-
-	case SNDCTL_DSP_GETCAPS:
-		ival = DSP_CAP_DUPLEX;
-		return put_user(ival, (int *) arg);
-
-	case SNDCTL_DSP_GETFMTS:
-		ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW ); 
-		return put_user(ival, (int *) arg);
-	
-	case SNDCTL_DSP_SETFMT:
-		if (get_user(ival, (int *) arg)) 
-			return -EFAULT;
-		if (ival != AFMT_QUERY) {
-			switch (ival) {
-			case AFMT_MU_LAW:	new_format = HARMONY_DF_8BIT_ULAW; break;
-			case AFMT_A_LAW:	new_format = HARMONY_DF_8BIT_ALAW; break;
-			case AFMT_S16_BE:	new_format = HARMONY_DF_16BIT_LINEAR; break;
-			default: {
-				DPRINTK(KERN_WARNING PFX 
-					"unsupported sound format 0x%04x requested.\n",
-					ival);
-				ival = AFMT_S16_BE;
-				return put_user(ival, (int *) arg);
-			}
-			}
-			harmony_set_format(new_format);
-			return 0;
-		} else {
-			switch (harmony.data_format) {
-			case HARMONY_DF_8BIT_ULAW:	ival = AFMT_MU_LAW; break;
-			case HARMONY_DF_8BIT_ALAW:	ival = AFMT_A_LAW;  break;
-			case HARMONY_DF_16BIT_LINEAR:	ival = AFMT_U16_BE; break;
-			default: ival = 0;
-			}
-			return put_user(ival, (int *) arg);
-		}
-
-	case SOUND_PCM_READ_RATE:
-		ival = harmony.dac_rate;
-		return put_user(ival, (int *) arg);
-
-	case SNDCTL_DSP_SPEED:
-		if (get_user(ival, (int *) arg))
-			return -EFAULT;
-		harmony_set_rate(harmony_detect_rate(&ival));
-		harmony.dac_rate = ival;
-		return put_user(ival, (int*) arg);
-
-	case SNDCTL_DSP_STEREO:
-		if (get_user(ival, (int *) arg))
-			return -EFAULT;
-		if (ival != 0 && ival != 1)
-			return -EINVAL;
-		harmony_set_stereo(ival);
- 		return 0;
- 
- 	case SNDCTL_DSP_CHANNELS:
- 		if (get_user(ival, (int *) arg))
- 			return -EFAULT;
- 		if (ival != 1 && ival != 2) {
- 			ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2;
- 			return put_user(ival, (int *) arg);
- 		}
- 		harmony_set_stereo(ival-1);
- 		return 0;
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		ival = HARMONY_BUF_SIZE;
-		return put_user(ival, (int *) arg);
-		
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_RESET:
-		if (!harmony.suspended_recording) {
-			/* TODO: stop_recording() */
-		}
-		return 0;
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(ival, (int *)arg))
-			return -EFAULT;
-		frag_size = ival & 0xffff;
-		frag_buf = (ival>>16) & 0xffff;
-		/* TODO: We use hardcoded fragment sizes and numbers for now */
-		frag_size = 12;  /* 4096 == 2^12 */
-		frag_buf  = MAX_BUFS;
-		ival = (frag_buf << 16) + frag_size;
-		return put_user(ival, (int *) arg);
-		
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		info.fragstotal = MAX_BUFS;
-                info.fragments = MAX_BUFS - harmony.nb_filled_play;
-		info.fragsize = HARMONY_BUF_SIZE;
-                info.bytes = info.fragments * info.fragsize;
-		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		info.fragstotal = MAX_BUFS;
-                info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record;
-		info.fragsize = HARMONY_BUF_SIZE;
-                info.bytes = info.fragments * info.fragsize;
-		return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-	
-	case SNDCTL_DSP_SYNC:
-		return 0;
-	}
-	
-	return -EINVAL;
-}
-
-
-/*
- * harmony_interrupt()
- *
- * harmony interruption service routine
- * 
- */
-
-static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
-{
-	u32 dstatus;
-	struct harmony_hpa *hpa;
-
-	/* Setup the hpa */
-	hpa = ((struct harmony_dev *)dev)->hpa;
-	harmony_wait_CNTL();
-
-	/* Read dstatus and pcuradd (the current address) */
-	dstatus = gsc_readl(&hpa->dstatus);
-	
-	/* Turn off interrupts */
-	harmony_disable_interrupts();
-	
-	/* Check if this is a request to get the next play buffer */
-	if (dstatus & DSTATUS_PN) {
-		if (!harmony.nb_filled_play) {
-			harmony.suspended_playing = 1;
-			gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd);
-						
-			if (!harmony.suspended_recording)
-				harmony_enable_interrupts();
-		} else {
-			harmony.suspended_playing = 0;
-			gsc_writel((unsigned long)played_buf.dma_handle + 
-					(HARMONY_BUF_SIZE*harmony.first_filled_play),
-					&hpa->pnxtadd);
-			harmony.first_filled_play++;
-			harmony.first_filled_play %= MAX_BUFS;
-			harmony.nb_filled_play--;
-			
-		       	harmony_enable_interrupts();
-		}
-		
-		if (harmony.blocked_playing)
-			wake_up_interruptible(&harmony.wq_play);
-	}
-	
-	/* Check if we're being asked to fill in a recording buffer */
-	if (dstatus & DSTATUS_RN) {
-		if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)
-		{
-			harmony.nb_filled_record = 0;
-			harmony.first_filled_record = 0;
-			harmony.suspended_recording = 1;
-			gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd);
-			if (!harmony.suspended_playing)
-				harmony_enable_interrupts();
-		} else {
-			int buf_to_fill;
-			buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS;
-			CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE);
-			gsc_writel((unsigned long)recorded_buf.dma_handle +
-					HARMONY_BUF_SIZE*buf_to_fill,
-					&hpa->rnxtadd);
-			harmony.nb_filled_record++;
-			harmony_enable_interrupts();
-		}
-
-		if (harmony.blocked_recording && harmony.nb_filled_record>3)
-			wake_up_interruptible(&harmony.wq_record);
-	}
-	return IRQ_HANDLED;
-}
-
-/*
- * Sound playing functions
- */
-
-static struct file_operations harmony_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= harmony_audio_read,
-	.write		= harmony_audio_write,
-	.poll		= harmony_audio_poll,
-	.ioctl		= harmony_audio_ioctl,
-	.open		= harmony_audio_open,
-	.release	= harmony_audio_release,
-};
-
-static int harmony_audio_init(void)
-{
-	/* Request that IRQ */
-	if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) {
-		printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq);
-		return -EFAULT;
-	}
-
-   	harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1);
-	if (harmony.dsp_unit < 0) {
-		printk(KERN_ERR PFX "Error registering dsp\n");
-		free_irq(harmony.dev->irq, &harmony);
-		return -EFAULT;
-	}
-	
-	/* Clear the buffers so you don't end up with crap in the buffers. */ 
-	harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
-	/* Make sure this makes it to cache */
-	CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
-	/* Clear out the silent buffer and flush to cache */
-	harmony_silence(&silent, 0, HARMONY_BUF_SIZE);
-	CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE);
-	
-	harmony.audio_open = 0;
-	
-	return 0;
-}
-
-
-/*
- * mixer functions 
- */
-
-static void harmony_mixer_set_gain(void)
-{
-	harmony_wait_CNTL();
-	gsc_writel(harmony.current_gain, &harmony.hpa->gainctl);
-}
-
-/* 
- *  Read gain of selected channel.
- *  The OSS rate is from 0 (silent) to 100 -> need some conversions
- *
- *  The harmony gain are attenuation for output and monitor gain.
- *                   is amplifaction for input gain
- */
-#define to_harmony_level(level,max) ((level)*max/100)
-#define to_oss_level(level,max) ((level)*100/max)
-
-static int harmony_mixer_get_level(int channel)
-{
-	int left_level;
-	int right_level;
-
-	switch (channel) {
-		case SOUND_MIXER_VOLUME:
-			left_level  = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT;
-			right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT;
-			left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
-			right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
-			return (right_level << 8)+left_level;
-			
-		case SOUND_MIXER_IGAIN:
-			left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT;
-			right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT;
-			left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
-			right_level= to_oss_level(right_level, MAX_INPUT_LEVEL);
-			return (right_level << 8)+left_level;
-			
-		case SOUND_MIXER_MONITOR:
-			left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT;
-			left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
-			return (left_level << 8)+left_level;
-	}
-	return -EINVAL;
-}
-
-
-
-/*
- * Some conversions for the same reasons.
- * We give back the new real value(s) due to
- * the rescale.
- */
-
-static int harmony_mixer_set_level(int channel, int value)
-{
-	int left_level;
-	int right_level;
-	int new_left_level;
-	int new_right_level;
-
-	right_level = (value & 0x0000ff00) >> 8;
-	left_level = value & 0x000000ff;
-	if (right_level > 100) right_level = 100;
-	if (left_level > 100) left_level = 100;
-  
-	switch (channel) {
-		case SOUND_MIXER_VOLUME:
-			right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL);
-			left_level  = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL);
-			new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
-			new_left_level  = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
-			harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK)) 
-					| (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT);
-			harmony_mixer_set_gain();
-			return (new_right_level << 8) + new_left_level;
-			
-		case SOUND_MIXER_IGAIN:
-			right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL);
-			left_level  = to_harmony_level(left_level, MAX_INPUT_LEVEL);
-			new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL);
-			new_left_level  = to_oss_level(left_level, MAX_INPUT_LEVEL);
-			harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK))
-					| (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT);
-			harmony_mixer_set_gain();
-			return (new_right_level << 8) + new_left_level;
-	
-		case SOUND_MIXER_MONITOR:
-			left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL);
-			new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
-			harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT);
-			harmony_mixer_set_gain();
-			return (new_left_level << 8) + new_left_level;
-	}
-
-	return -EINVAL;
-}
-
-#undef to_harmony_level
-#undef to_oss_level
-
-/* 
- * Return the selected input device (mic or line)
- */
-
-static int harmony_mixer_get_recmask(void) 
-{
-	int current_input_line;
-	
-	current_input_line = (harmony.current_gain & GAIN_IS_MASK) 
-				    >> GAIN_IS_SHIFT;
-	if (current_input_line) 
-		return SOUND_MASK_MIC;
-
-	return SOUND_MASK_LINE;
-}
-
-/*
- * Set the input (only one at time, arbitrary priority to line in)
- */
-
-static int harmony_mixer_set_recmask(int recmask)
-{
-	int new_input_line;
-	int new_input_mask;
-	int current_input_line;
-	
-	current_input_line = (harmony.current_gain & GAIN_IS_MASK)
-				    >> GAIN_IS_SHIFT;
-	if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) ||
-		(!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) {
-		new_input_line = 0;
-		new_input_mask = SOUND_MASK_LINE;
-	} else {
-		new_input_line = 1;
-		new_input_mask = SOUND_MASK_MIC;
-	}
-	harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) | 
-				(new_input_line << GAIN_IS_SHIFT ));
-	harmony_mixer_set_gain();
-	return new_input_mask;
-}
-
-
-/* 
- * give the active outlines
- */
-
-static int harmony_mixer_get_outmask(void)
-{
-	int outmask = 0;
-	
-	if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL;
-	if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT;
-	if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES;
-	
-	return outmask;
-}
-
-
-static int harmony_mixer_set_outmask(int outmask)
-{
-	if (outmask & MASK_INTERNAL) 
-		harmony.current_gain |= GAIN_SE_MASK;
-	else 
-		harmony.current_gain &= ~GAIN_SE_MASK;
-	
-	if (outmask & MASK_LINEOUT) 
-		harmony.current_gain |= GAIN_LE_MASK;
-	else 
-		harmony.current_gain &= ~GAIN_LE_MASK;
-	
-	if (outmask & MASK_HEADPHONES) 
-		harmony.current_gain |= GAIN_HE_MASK; 
-	else 
-		harmony.current_gain &= ~GAIN_HE_MASK;
-	
-	harmony_mixer_set_gain();
-
-	return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES));
-}
-
-/*
- * This code is inspired from sb_mixer.c
- */
-
-static int harmony_mixer_ioctl(struct inode * inode, struct file * file,
-		unsigned int cmd, unsigned long arg)
-{
-	int val;
-	int ret;
-
-	if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		memset(&info, 0, sizeof(info));
-                strncpy(info.id, "harmony", sizeof(info.id)-1);
-                strncpy(info.name, "Harmony audio", sizeof(info.name)-1);
-                info.modify_counter = 1; /* ? */
-                if (copy_to_user((void *)arg, &info, sizeof(info)))
-                        return -EFAULT;
-		return 0;
-	}
-	
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, (int *)arg);
-
-	/* read */
-	val = 0;
-	if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-		if (get_user(val, (int *)arg))
-			return -EFAULT;
-
-	switch (cmd) {
-	case MIXER_READ(SOUND_MIXER_CAPS):
-		ret = SOUND_CAP_EXCL_INPUT;
-		break;
-	case MIXER_READ(SOUND_MIXER_STEREODEVS):
-		ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
-		break;
-		
-	case MIXER_READ(SOUND_MIXER_RECMASK):
-		ret = SOUND_MASK_MIC | SOUND_MASK_LINE;
-		break;
-	case MIXER_READ(SOUND_MIXER_DEVMASK):
-		ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN |
-			SOUND_MASK_MONITOR;
-		break;
-	case MIXER_READ(SOUND_MIXER_OUTMASK):
-		ret = MASK_INTERNAL | MASK_LINEOUT |
-			MASK_HEADPHONES;
-		break;
-		
-	case MIXER_WRITE(SOUND_MIXER_RECSRC):
-		ret = harmony_mixer_set_recmask(val);
-		break;
-	case MIXER_READ(SOUND_MIXER_RECSRC):
-		ret = harmony_mixer_get_recmask();
-		break;
-	      
-	case MIXER_WRITE(SOUND_MIXER_OUTSRC):
-		ret = harmony_mixer_set_outmask(val);
-		break;
-	case MIXER_READ(SOUND_MIXER_OUTSRC):
-		ret = harmony_mixer_get_outmask();
-		break;
-	
-	case MIXER_WRITE(SOUND_MIXER_VOLUME):
-	case MIXER_WRITE(SOUND_MIXER_IGAIN):
-	case MIXER_WRITE(SOUND_MIXER_MONITOR):
-		ret = harmony_mixer_set_level(cmd & 0xff, val);
-		break;
-
-	case MIXER_READ(SOUND_MIXER_VOLUME):
-	case MIXER_READ(SOUND_MIXER_IGAIN):
-	case MIXER_READ(SOUND_MIXER_MONITOR):
-		ret = harmony_mixer_get_level(cmd & 0xff);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	if (put_user(ret, (int *)arg))
-		return -EFAULT;
-	return 0;
-}
-
-
-static int harmony_mixer_open(struct inode *inode, struct file *file)
-{
-	if (harmony.mixer_open) 
-		return -EBUSY;
-	harmony.mixer_open = 1;
-	return 0;
-}
-
-static int harmony_mixer_release(struct inode *inode, struct file *file)
-{
-	if (!harmony.mixer_open) 
-		return -EBUSY;
-	harmony.mixer_open = 0;
-	return 0;
-}
-
-static struct file_operations harmony_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.open		= harmony_mixer_open,
-	.release	= harmony_mixer_release,
-	.ioctl		= harmony_mixer_ioctl,
-};
-
-
-/*
- * Mute all the output and reset Harmony.
- */
-
-static void __init harmony_mixer_reset(void)
-{
-	harmony.current_gain = GAIN_TOTAL_SILENCE;
-	harmony_mixer_set_gain();
-	harmony_wait_CNTL();
-	gsc_writel(1, &harmony.hpa->reset);
-	mdelay(50);		/* wait 50 ms */
-	gsc_writel(0, &harmony.hpa->reset);
-	harmony.current_gain = GAIN_DEFAULT;
-	harmony_mixer_set_gain();
-}
-
-static int __init harmony_mixer_init(void)
-{
-	/* Register the device file operations */
-	harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1);
-	if (harmony.mixer_unit < 0) {
-		printk(KERN_WARNING PFX "Error Registering Mixer Driver\n");
-		return -EFAULT;
-	}
-  
-	harmony_mixer_reset();
-	harmony.mixer_open = 0;
-	
-	return 0;
-}
-
-
-
-/* 
- * This is the callback that's called by the inventory hardware code 
- * if it finds a match to the registered driver. 
- */
-static int __devinit
-harmony_driver_probe(struct parisc_device *dev)
-{
-	u8	id;
-	u8	rev;
-	u32	cntl;
-	int	ret;
-
-	if (harmony.hpa) {
-		/* We only support one Harmony at this time */
-		printk(KERN_ERR PFX "driver already registered\n");
-		return -EBUSY;
-	}
-
-	if (!dev->irq) {
-		printk(KERN_ERR PFX "no irq found\n");
-		return -ENODEV;
-	}
-
-	/* Set the HPA of harmony */
-	harmony.hpa = (struct harmony_hpa *)dev->hpa.start;
-	harmony.dev = dev;
-
-	/* Grab the ID and revision from the device */
-	id = gsc_readb(&harmony.hpa->id);
-	if ((id | 1) != 0x15) {
-		printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id);
-		return -EBUSY;
-	}
-	cntl = gsc_readl(&harmony.hpa->cntl);
-	rev = (cntl>>20) & 0xff;
-
-	printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", "
-			"h/w id %i, rev. %i at 0x%lx, IRQ %i\n",
-			id, rev, dev->hpa.start, harmony.dev->irq);
-	
-	/* Make sure the control bit isn't set, although I don't think it 
-	   ever is. */
-	if (cntl & CNTL_C) {
-		printk(KERN_WARNING PFX "CNTL busy\n");
-		harmony.hpa = 0;
-		return -EBUSY;
-	}
-
-	/* Initialize the memory buffers */
-	if (harmony_alloc_buffer(&played_buf, MAX_BUFS) || 
-	    harmony_alloc_buffer(&recorded_buf, MAX_BUFS) ||
-	    harmony_alloc_buffer(&graveyard, 1) ||
-	    harmony_alloc_buffer(&silent, 1)) {
-		ret = -EBUSY;
-		goto out_err;
-	}
-
-	/* Initialize /dev/mixer and /dev/audio  */
-	if ((ret=harmony_mixer_init())) 
-		goto out_err;
-	if ((ret=harmony_audio_init())) 
-		goto out_err;
-
-	return 0;
-
-out_err:
-	harmony.hpa = 0;
-	harmony_free_buffer(&played_buf);
-	harmony_free_buffer(&recorded_buf);
-	harmony_free_buffer(&graveyard);
-	harmony_free_buffer(&silent);
-	return ret;
-}
-
-
-static struct parisc_device_id harmony_tbl[] = {
- /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(parisc, harmony_tbl);
-
-static struct parisc_driver harmony_driver = {
-	.name		= "Lasi Harmony",
-	.id_table	= harmony_tbl,
-	.probe		= harmony_driver_probe,
-};
-
-static int __init init_harmony(void)
-{
-	return register_parisc_driver(&harmony_driver);
-}
-
-static void __exit cleanup_harmony(void)
-{
-	free_irq(harmony.dev->irq, &harmony);
-	unregister_sound_mixer(harmony.mixer_unit);
-	unregister_sound_dsp(harmony.dsp_unit);
-	harmony_free_buffer(&played_buf);
-	harmony_free_buffer(&recorded_buf);
-	harmony_free_buffer(&graveyard);
-	harmony_free_buffer(&silent);
-	unregister_parisc_driver(&harmony_driver);
-}
-
-
-MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>");
-MODULE_DESCRIPTION("Harmony sound driver");
-MODULE_LICENSE("GPL");
-
-module_init(init_harmony);
-module_exit(cleanup_harmony);
-
diff --git a/sound/oss/ics2101.c b/sound/oss/ics2101.c
deleted file mode 100644
index 45918df..0000000
--- a/sound/oss/ics2101.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * sound/oss/ics2101.c
- *
- * Driver for the ICS2101 mixer of GUS v3.7.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *
- * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
- * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
- */
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include <linux/ultrasound.h>
-
-#include "gus.h"
-#include "gus_hw.h"
-
-#define MIX_DEVS	(SOUND_MASK_MIC|SOUND_MASK_LINE| \
-			 SOUND_MASK_SYNTH| \
-  			 SOUND_MASK_CD | SOUND_MASK_VOLUME)
-
-extern int     *gus_osp;
-extern int      gus_base;
-extern spinlock_t gus_lock;
-static int      volumes[ICS_MIXDEVS];
-static int      left_fix[ICS_MIXDEVS] =
-{1, 1, 1, 2, 1, 2};
-static int      right_fix[ICS_MIXDEVS] =
-{2, 2, 2, 1, 2, 1};
-
-static int scale_vol(int vol)
-{
-	/*
-	 *  Experimental volume scaling by Risto Kankkunen.
-	 *  This should give smoother volume response than just
-	 *  a plain multiplication.
-	 */
-	 
-	int e;
-
-	if (vol < 0)
-		vol = 0;
-	if (vol > 100)
-		vol = 100;
-	vol = (31 * vol + 50) / 100;
-	e = 0;
-	if (vol)
-	{
-		while (vol < 16)
-		{
-			vol <<= 1;
-			e--;
-		}
-		vol -= 16;
-		e += 7;
-	}
-	return ((e << 4) + vol);
-}
-
-static void write_mix(int dev, int chn, int vol)
-{
-	int *selector;
-	unsigned long flags;
-	int ctrl_addr = dev << 3;
-	int attn_addr = dev << 3;
-
-	vol = scale_vol(vol);
-
-	if (chn == CHN_LEFT)
-	{
-		selector = left_fix;
-		ctrl_addr |= 0x00;
-		attn_addr |= 0x02;
-	}
-	else
-	{
-		selector = right_fix;
-		ctrl_addr |= 0x01;
-		attn_addr |= 0x03;
-	}
-
-	spin_lock_irqsave(&gus_lock, flags);
-	outb((ctrl_addr), u_MixSelect);
-	outb((selector[dev]), u_MixData);
-	outb((attn_addr), u_MixSelect);
-	outb(((unsigned char) vol), u_MixData);
-	spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int set_volumes(int dev, int vol)
-{
-	int left = vol & 0x00ff;
-	int right = (vol >> 8) & 0x00ff;
-
-	if (left < 0)
-		left = 0;
-	if (left > 100)
-		left = 100;
-	if (right < 0)
-		right = 0;
-	if (right > 100)
-		right = 100;
-
-	write_mix(dev, CHN_LEFT, left);
-	write_mix(dev, CHN_RIGHT, right);
-
-	vol = left + (right << 8);
-	volumes[dev] = vol;
-	return vol;
-}
-
-static int ics2101_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
-	int val;
-	
-	if (((cmd >> 8) & 0xff) == 'M') {
-		if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
-			
-			if (get_user(val, (int __user *)arg))
-				return -EFAULT;
-			switch (cmd & 0xff) {
-			case SOUND_MIXER_RECSRC:
-				return gus_default_mixer_ioctl(dev, cmd, arg);
-
-			case SOUND_MIXER_MIC:
-				val = set_volumes(DEV_MIC, val);
-				break;
-				
-			case SOUND_MIXER_CD:
-				val = set_volumes(DEV_CD, val);
-				break;
-
-			case SOUND_MIXER_LINE:
-				val = set_volumes(DEV_LINE, val);
-				break;
-
-			case SOUND_MIXER_SYNTH:
-				val = set_volumes(DEV_GF1, val);
-				break;
-
-			case SOUND_MIXER_VOLUME:
-				val = set_volumes(DEV_VOL, val);
-				break;
-
-			default:
-				return -EINVAL;
-			}
-			return put_user(val, (int __user *)arg);
-		} else {
-			switch (cmd & 0xff) {
-				/*
-				 * Return parameters
-				 */
-			case SOUND_MIXER_RECSRC:
-				return gus_default_mixer_ioctl(dev, cmd, arg);
-
-			case SOUND_MIXER_DEVMASK:
-				val = MIX_DEVS; 
-				break;
-
-			case SOUND_MIXER_STEREODEVS:
-				val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC; 
-				break;
-
-			case SOUND_MIXER_RECMASK:
-				val = SOUND_MASK_MIC | SOUND_MASK_LINE; 
-				break;
-				
-			case SOUND_MIXER_CAPS:
-				val = 0; 
-				break;
-
-			case SOUND_MIXER_MIC:
-				val = volumes[DEV_MIC];
-				break;
-				
-			case SOUND_MIXER_LINE:
-				val = volumes[DEV_LINE];
-				break;
-
-			case SOUND_MIXER_CD:
-				val = volumes[DEV_CD];
-				break;
-
-			case SOUND_MIXER_VOLUME:
-				val = volumes[DEV_VOL];
-				break;
-
-			case SOUND_MIXER_SYNTH:
-				val = volumes[DEV_GF1]; 
-				break;
-
-			default:
-				return -EINVAL;
-			}
-			return put_user(val, (int __user *)arg);
-		}
-	}
-	return -EINVAL;
-}
-
-static struct mixer_operations ics2101_mixer_operations =
-{
-	.owner	= THIS_MODULE,
-	.id	= "ICS2101",
-	.name	= "ICS2101 Multimedia Mixer",
-	.ioctl	= ics2101_mixer_ioctl
-};
-
-int __init ics2101_mixer_init(void)
-{
-	int i;
-	int n;
-
-	if ((n = sound_alloc_mixerdev()) != -1)
-	{
-		mixer_devs[n] = &ics2101_mixer_operations;
-
-		/*
-		 * Some GUS v3.7 cards had some channels flipped. Disable
-		 * the flipping feature if the model id is other than 5.
-		 */
-
-		if (inb(u_MixSelect) != 5)
-		{
-			for (i = 0; i < ICS_MIXDEVS; i++)
-				left_fix[i] = 1;
-			for (i = 0; i < ICS_MIXDEVS; i++)
-				right_fix[i] = 2;
-		}
-		set_volumes(DEV_GF1, 0x5a5a);
-		set_volumes(DEV_CD, 0x5a5a);
-		set_volumes(DEV_MIC, 0x0000);
-		set_volumes(DEV_LINE, 0x5a5a);
-		set_volumes(DEV_VOL, 0x5a5a);
-		set_volumes(DEV_UNUSED, 0x0000);
-	}
-	return n;
-}
diff --git a/sound/oss/iwmem.h b/sound/oss/iwmem.h
deleted file mode 100644
index 48d333c..0000000
--- a/sound/oss/iwmem.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * sound/oss/iwmem.h
- *
- * DRAM size encoding table for AMD Interwave chip.
- */
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * Bartlomiej Zolnierkiewicz	: added __initdata to mem_decode
- */
-
-
-#define K 1024
-#define M (1024*K)
-static int mem_decode[][4] __initdata =
-{
-/*	Bank0	Bank1	Bank2	Bank3	Encoding bits	*/
-	{256*K,	0,	0,	0},		/*  0 */
-	{256*K,	256*K,	0,	0},		/*  1 */
-	{256*K,	256*K,	256*K,	256*K},		/*  2 */
-	{256*K,	1*M,	0,	0},		/*  3 */
-	{256*K,	1*M,	1*M,	1*M},		/*  4 */
-	{256*K,	256*K,	1*M,	0},		/*  5 */
-	{256*K,	256*K,	1*M,	1*M},		/*  6 */
-	{1*M,	0,	0,	0},		/*  7 */
-	{1*M,	1*M,	0,	0},		/*  8 */
-	{1*M,	1*M,	1*M,	1*M},		/*  9 */
-	{4*M,	0,	0,	0},		/* 10 */
-	{4*M,	4*M,	0,	0},		/* 11 */
-	{4*M,	4*M,	4*M,	4*M}		/* 12 */
-};
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
deleted file mode 100644
index aa3c50d..0000000
--- a/sound/oss/mad16.c
+++ /dev/null
@@ -1,1113 +0,0 @@
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * mad16.c
- *
- * Initialization code for OPTi MAD16 compatible audio chips. Including
- *
- *      OPTi 82C928     MAD16           (replaced by C929)
- *      OAK OTI-601D    Mozart
- *      OAK OTI-605	Mozart		(later version with MPU401 Midi)
- *      OPTi 82C929     MAD16 Pro
- *      OPTi 82C930
- *      OPTi 82C924
- *
- * These audio interface chips don't produce sound themselves. They just
- * connect some other components (OPL-[234] and a WSS compatible codec)
- * to the PC bus and perform I/O, DMA and IRQ address decoding. There is
- * also a UART for the MPU-401 mode (not 82C928/Mozart).
- * The Mozart chip appears to be compatible with the 82C928, although later
- * issues of the card, using the OTI-605 chip, have an MPU-401 compatible Midi
- * port. This port is configured differently to that of the OPTi audio chips.
- *
- *	Changes
- *	
- *	Alan Cox		Clean up, added module selections.
- *
- *	A. Wik			Added support for Opti924 PnP.
- *				Improved debugging support.	16-May-1998
- *				Fixed bug.			16-Jun-1998
- *
- *      Torsten Duwe            Made Opti924 PnP support non-destructive
- *                                                             	23-Dec-1998
- *
- *	Paul Grayson		Added support for Midi on later Mozart cards.
- *								25-Nov-1999
- *	Christoph Hellwig	Adapted to module_init/module_exit.
- *	Arnaldo C. de Melo	got rid of attach_uart401       21-Sep-2000
- *
- *	Pavel Rabel		Clean up                           Nov-2000
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gameport.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "sb.h"
-#include "mpu401.h"
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-static int      mad16_conf;
-static int      mad16_cdsel;
-static DEFINE_SPINLOCK(lock);
-
-#define C928	1
-#define MOZART	2
-#define C929	3
-#define C930	4
-#define C924    5
-
-/*
- *    Registers
- *
- *      The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations).
- *      All ports are inactive by default. They can be activated by
- *      writing 0xE2 or 0xE3 to the password register. The password is valid
- *      only until the next I/O read or write.
- *
- *      82C930 uses 0xE4 as the password and indirect addressing to access
- *      the config registers.
- */
-
-#define MC0_PORT	0xf8c	/* Dummy port */
-#define MC1_PORT	0xf8d	/* SB address, CD-ROM interface type, joystick */
-#define MC2_PORT	0xf8e	/* CD-ROM address, IRQ, DMA, plus OPL4 bit */
-#define MC3_PORT	0xf8f
-#define PASSWD_REG	0xf8f
-#define MC4_PORT	0xf90
-#define MC5_PORT	0xf91
-#define MC6_PORT	0xf92
-#define MC7_PORT	0xf93
-#define MC8_PORT	0xf94
-#define MC9_PORT	0xf95
-#define MC10_PORT	0xf96
-#define MC11_PORT	0xf97
-#define MC12_PORT	0xf98
-
-static int      board_type = C928;
-
-static int     *mad16_osp;
-static int	c931_detected;	/* minor differences from C930 */
-static char	c924pnp;	/* "     "           "    C924 */
-static int	debug;  	/* debugging output */
-
-#ifdef DDB
-#undef DDB
-#endif
-#define DDB(x) do {if (debug) x;} while (0)
-
-static unsigned char mad_read(int port)
-{
-	unsigned long flags;
-	unsigned char tmp;
-
-	spin_lock_irqsave(&lock,flags);
-
-	switch (board_type)	/* Output password */
-	{
-		case C928:
-		case MOZART:
-			outb((0xE2), PASSWD_REG);
-			break;
-
-		case C929:
-			outb((0xE3), PASSWD_REG);
-			break;
-
-		case C930:
-			/* outb(( 0xE4),  PASSWD_REG); */
-			break;
-
-		case C924:
-			/* the c924 has its ports relocated by -128 if
-			   PnP is enabled  -aw */
-			if (!c924pnp)
-				outb((0xE5), PASSWD_REG); else
-				outb((0xE5), PASSWD_REG - 0x80);
-			break;
-	}
-
-	if (board_type == C930)
-	{
-		outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */
-		tmp = inb(0xe0f);	/* Read from data reg */
-	}
-	else
-		if (!c924pnp)
-			tmp = inb(port); else
-			tmp = inb(port-0x80);
-	spin_unlock_irqrestore(&lock,flags);
-
-	return tmp;
-}
-
-static void mad_write(int port, int value)
-{
-	unsigned long   flags;
-
-	spin_lock_irqsave(&lock,flags);
-
-	switch (board_type)	/* Output password */
-	{
-		case C928:
-		case MOZART:
-			outb((0xE2), PASSWD_REG);
-			break;
-
-		case C929:
-			outb((0xE3), PASSWD_REG);
-			break;
-
-		case C930:
-			/* outb(( 0xE4),  PASSWD_REG); */
-			break;
-
-		case C924:
-			if (!c924pnp)
-				outb((0xE5), PASSWD_REG); else
-				outb((0xE5), PASSWD_REG - 0x80);
-			break;
-	}
-
-	if (board_type == C930)
-	{
-		outb((port - MC0_PORT), 0xe0e);	/* Write to index reg */
-		outb(((unsigned char) (value & 0xff)), 0xe0f);
-	}
-	else
-		if (!c924pnp)
-			outb(((unsigned char) (value & 0xff)), port); else
-			outb(((unsigned char) (value & 0xff)), port-0x80);
-	spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init detect_c930(void)
-{
-	unsigned char   tmp = mad_read(MC1_PORT);
-
-	if ((tmp & 0x06) != 0x06)
-	{
-		DDB(printk("Wrong C930 signature (%x)\n", tmp));
-		/* return 0; */
-	}
-	mad_write(MC1_PORT, 0);
-
-	if (mad_read(MC1_PORT) != 0x06)
-	{
-		DDB(printk("Wrong C930 signature2 (%x)\n", tmp));
-		/* return 0; */
-	}
-	mad_write(MC1_PORT, tmp);	/* Restore bits */
-
-	mad_write(MC7_PORT, 0);
-	if ((tmp = mad_read(MC7_PORT)) != 0)
-	{
-		DDB(printk("MC7 not writable (%x)\n", tmp));
-		return 0;
-	}
-	mad_write(MC7_PORT, 0xcb);
-	if ((tmp = mad_read(MC7_PORT)) != 0xcb)
-	{
-		DDB(printk("MC7 not writable2 (%x)\n", tmp));
-		return 0;
-	}
-
-	tmp = mad_read(MC0_PORT+18);
-	if (tmp == 0xff || tmp == 0x00)
-		return 1;
-	/* We probably have a C931 */
-	DDB(printk("Detected C931 config=0x%02x\n", tmp));
-	c931_detected = 1;
-
-	/*
-         * We cannot configure the chip if it is in PnP mode.
-         * If we have a CSN assigned (bit 8 in MC13) we first try
-         * a software reset, then a software power off, finally
-         * Clearing PnP mode. The last option is not
-	 * Bit 8 in MC13 
-         */
-	if ((mad_read(MC0_PORT+13) & 0x80) == 0)
-		return 1;
-
-	/* Software reset */
-	mad_write(MC9_PORT, 0x02);
-	mad_write(MC9_PORT, 0x00);
-
-	if ((mad_read(MC0_PORT+13) & 0x80) == 0)
-		return 1;
-	
-	/* Power off, and on again */
-	mad_write(MC9_PORT, 0xc2);
-	mad_write(MC9_PORT, 0xc0);
-
-	if ((mad_read(MC0_PORT+13) & 0x80) == 0)
-		return 1;
-	
-#if 0	
-	/* Force off PnP mode. This is not recommended because
-	 * the PnP bios will not recognize the chip on the next
-	 * warm boot and may assignd different resources to other
-	 * PnP/PCI cards.
-	 */
-	mad_write(MC0_PORT+17, 0x04);
-#endif
-	return 1;
-}
-
-static int __init detect_mad16(void)
-{
-	unsigned char tmp, tmp2, bit;
-	int i, port;
-
-	/*
-	 * Check that reading a register doesn't return bus float (0xff)
-	 * when the card is accessed using password. This may fail in case
-	 * the card is in low power mode. Normally at least the power saving
-	 * mode bit should be 0.
-	 */
-
-	if ((tmp = mad_read(MC1_PORT)) == 0xff)
-	{
-		DDB(printk("MC1_PORT returned 0xff\n"));
-		return 0;
-	}
-	for (i = 0xf8d; i <= 0xf98; i++)
-		if (!c924pnp)
-			DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i)));
-		else
-			DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i)));
-
-	if (board_type == C930)
-		return detect_c930();
-
-	/*
-	 * Now check that the gate is closed on first I/O after writing
-	 * the password. (This is how a MAD16 compatible card works).
-	 */
-
-	if ((tmp2 = inb(MC1_PORT)) == tmp)	/* It didn't close */
-	{
-		DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
-		return 0;
-	}
-
-	bit  = (c924pnp) ?     0x20 : 0x80;
-	port = (c924pnp) ? MC2_PORT : MC1_PORT;
-
-	tmp = mad_read(port);
-	mad_write(port, tmp ^ bit);	/* Toggle a bit */
-	if ((tmp2 = mad_read(port)) != (tmp ^ bit))	/* Compare the bit */
-	{
-		mad_write(port, tmp);	/* Restore */
-		DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
-		return 0;
-	}
-	mad_write(port, tmp);	/* Restore */
-	return 1;		/* Bingo */
-}
-
-static int __init wss_init(struct address_info *hw_config)
-{
-	/*
-	 * Check if the IO port returns valid signature. The original MS Sound
-	 * system returns 0x04 while some cards (AudioTrix Pro for example)
-	 * return 0x00.
-	 */
-
-	if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
-	    (inb(hw_config->io_base + 3) & 0x3f) != 0x00)
-	{
-		DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));
-		return 0;
-	}
-	/*
-	 * Check that DMA0 is not in use with a 8 bit board.
-	 */
-	if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)
-	{
-		printk("MSS: Can't use DMA0 with a 8 bit card/slot\n");
-		return 0;
-	}
-	if (hw_config->irq > 9 && inb(hw_config->io_base + 3) & 0x80)
-		printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
-	return 1;
-}
-
-static void __init init_c930(struct address_info *hw_config, int base)
-{
-	unsigned char cfg = 0;
-
-	cfg |= (0x0f & mad16_conf);
-
-	if(c931_detected)
-	{
-		/* Bit 0 has reversd meaning. Bits 1 and 2 sese
-		   reversed on write.
-		   Support only IDE cdrom. IDE port programmed
-		   somewhere else. */
-		cfg =  (cfg & 0x09) ^ 0x07;
-	}
-	cfg |= base << 4;
-	mad_write(MC1_PORT, cfg);
-
-	/* MC2 is CD configuration. Don't touch it. */
-
-	mad_write(MC3_PORT, 0);	/* Disable SB mode IRQ and DMA */
-
-	/* bit 2 of MC4 reverses it's meaning between the C930
-	   and the C931. */
-	cfg = c931_detected ? 0x04 : 0x00;
-
-	if(mad16_cdsel & 0x20)
-		mad_write(MC4_PORT, 0x62|cfg);  /* opl4 */
-	else
-		mad_write(MC4_PORT, 0x52|cfg);  /* opl3 */
-
-	mad_write(MC5_PORT, 0x3C);	/* Init it into mode2 */
-	mad_write(MC6_PORT, 0x02);	/* Enable WSS, Disable MPU and SB */
-	mad_write(MC7_PORT, 0xCB);
-	mad_write(MC10_PORT, 0x11);
-}
-
-static int __init chip_detect(void)
-{
-	int i;
-
-	/*
-	 *    Then try to detect with the old password
-	 */
-	board_type = C924;
-
-	DDB(printk("Detect using password = 0xE5\n"));
-	
-	if (detect_mad16()) {
-		return 1;
-	}
-	
-	board_type = C928;
-
-	DDB(printk("Detect using password = 0xE2\n"));
-
-	if (detect_mad16())
-	{
-		unsigned char model;
-
-		if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
-			DDB(printk("mad16.c: Mozart detected\n"));
-			board_type = MOZART;
-		} else {
-			DDB(printk("mad16.c: 82C928 detected???\n"));
-			board_type = C928;
-		}
-		return 1;
-	}
-
-	board_type = C929;
-
-	DDB(printk("Detect using password = 0xE3\n"));
-
-	if (detect_mad16())
-	{
-		DDB(printk("mad16.c: 82C929 detected\n"));
-		return 1;
-	}
-
-	if (inb(PASSWD_REG) != 0xff)
-		return 0;
-
-	/*
-	 * First relocate MC# registers to 0xe0e/0xe0f, disable password 
-	 */
-
-	outb((0xE4), PASSWD_REG);
-	outb((0x80), PASSWD_REG);
-
-	board_type = C930;
-
-	DDB(printk("Detect using password = 0xE4\n"));
-
-	for (i = 0xf8d; i <= 0xf93; i++)
-		DDB(printk("port %03x = %02x\n", i, mad_read(i)));
-
-        if(detect_mad16()) {
-		DDB(printk("mad16.c: 82C930 detected\n"));
-		return 1;
-	}
-
-	/* The C931 has the password reg at F8D */
-	outb((0xE4), 0xF8D);
-	outb((0x80), 0xF8D);
-	DDB(printk("Detect using password = 0xE4 for C931\n"));
-
-	if (detect_mad16()) {
-		return 1;
-	}
-
-	board_type = C924;
-	c924pnp++;
-	DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
-	if (detect_mad16()) {
-		DDB(printk("mad16.c: 82C924 PnP detected\n"));
-		return 1;
-	}
-	
-	c924pnp=0;
-
-	return 0;
-}
-
-static int __init probe_mad16(struct address_info *hw_config)
-{
-	int i;
-	unsigned char tmp;
-	unsigned char cs4231_mode = 0;
-
-	int ad_flags = 0;
-
-	signed char bits;
-
-	static char     dma_bits[4] = {
-		1, 2, 0, 3
-	};
-
-	int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
-	int dma = hw_config->dma, dma2 = hw_config->dma2;
-	unsigned char dma2_bit = 0;
-	int base;
-	struct resource *ports;
-
-	mad16_osp = hw_config->osp;
-
-	switch (hw_config->io_base) {
-	case 0x530:
-		base = 0;
-		break;
-	case 0xe80:
-		base = 1;
-		break;
-	case 0xf40:
-		base = 2;
-		break;
-	case 0x604:
-		base = 3;
-		break;
-	default:
-		printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
-		return 0;
-	}
-
-	if (dma != 0 && dma != 1 && dma != 3) {
-		printk(KERN_ERR "MSS: Bad DMA %d\n", dma);
-		return 0;
-	}
-
-	/*
-	 *    Check that all ports return 0xff (bus float) when no password
-	 *      is written to the password register.
-	 */
-
-	DDB(printk("--- Detecting MAD16 / Mozart ---\n"));
-	if (!chip_detect())
-		return 0;
-
-	switch (hw_config->irq) {
-	case 7:
-		bits = 8;
-		break;
-	case 9:
-		bits = 0x10;
-		break;
-	case 10:
-		bits = 0x18;
-		break;
-	case 12:
-		bits = 0x20;
-		break;
-	case 5:	/* Also IRQ5 is possible on C930 */
-		if (board_type == C930 || c924pnp) {
-			bits = 0x28;
-			break;
-		}
-	default:
-		printk(KERN_ERR "MAD16/Mozart: Bad IRQ %d\n", hw_config->irq);
-		return 0;
-	}
-
-	ports = request_region(hw_config->io_base + 4, 4, "ad1848");
-	if (!ports) {
-		printk(KERN_ERR "MSS: I/O port conflict\n");
-		return 0;
-	}
-	if (!request_region(hw_config->io_base, 4, "mad16 WSS config")) {
-		release_region(hw_config->io_base + 4, 4);
-		printk(KERN_ERR "MSS: I/O port conflict\n");
-		return 0;
-	}
-
-	if (board_type == C930) {
-		init_c930(hw_config, base);
-		goto got_it;
-	}
-
-	for (i = 0xf8d; i <= 0xf93; i++) {
-		if (!c924pnp)
-			DDB(printk("port %03x = %02x\n", i, mad_read(i)));
-		else
-			DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i)));
-	}
-
-/*
- * Set the WSS address
- */
-
-	tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80;	/* Enable WSS, Disable SB */
-	tmp |= base << 4;	/* WSS port select bits */
-
-	/*
-	 * Set optional CD-ROM and joystick settings.
-	 */
-
-	tmp &= ~0x0f;
-	tmp |= (mad16_conf & 0x0f);	/* CD-ROM and joystick bits */
-	mad_write(MC1_PORT, tmp);
-
-	tmp = mad16_cdsel;
-	mad_write(MC2_PORT, tmp);
-	mad_write(MC3_PORT, 0xf0);	/* Disable SB */
-
-	if (board_type == C924)	/* Specific C924 init values */
-	{
-		mad_write(MC4_PORT, 0xA0);
-		mad_write(MC5_PORT, 0x05);
-		mad_write(MC6_PORT, 0x03);
-	}
-	if (!ad1848_detect(ports, &ad_flags, mad16_osp))
-		goto fail;
-
-	if (ad_flags & (AD_F_CS4231 | AD_F_CS4248))
-		cs4231_mode = 0x02;	/* CS4248/CS4231 sync delay switch */
-
-	if (board_type == C929)
-	{
-		mad_write(MC4_PORT, 0xa2);
-		mad_write(MC5_PORT, 0xA5 | cs4231_mode);
-		mad_write(MC6_PORT, 0x03);	/* Disable MPU401 */
-	}
-	else
-	{
-		mad_write(MC4_PORT, 0x02);
-		mad_write(MC5_PORT, 0x30 | cs4231_mode);
-	}
-
-	for (i = 0xf8d; i <= 0xf93; i++) {
-		if (!c924pnp)
-			DDB(printk("port %03x after init = %02x\n", i, mad_read(i)));
-		else
-			DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i)));
-	}
-
-got_it:
-	ad_flags = 0;
-	if (!ad1848_detect(ports, &ad_flags, mad16_osp))
-		goto fail;
-
-	if (!wss_init(hw_config))
-		goto fail;
-
-	/*
-	 * Set the IRQ and DMA addresses.
-	 */
-	
-	outb((bits | 0x40), config_port);
-	if ((inb(version_port) & 0x40) == 0)
-		printk(KERN_ERR "[IRQ Conflict?]\n");
-
-	/*
-	 * Handle the capture DMA channel
-	 */
-
-	if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
-	{
-		if (!((dma == 0 && dma2 == 1) ||
-			(dma == 1 && dma2 == 0) ||
-			(dma == 3 && dma2 == 0)))
-		{		/* Unsupported combination. Try to swap channels */
-			int tmp = dma;
-
-			dma = dma2;
-			dma2 = tmp;
-		}
-		if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) ||
-			(dma == 3 && dma2 == 0))
-		{
-			dma2_bit = 0x04;	/* Enable capture DMA */
-		}
-		else
-		{
-			printk("MAD16: Invalid capture DMA\n");
-			dma2 = dma;
-		}
-	}
-	else dma2 = dma;
-
-	outb((bits | dma_bits[dma] | dma2_bit), config_port);	/* Write IRQ+DMA setup */
-
-	hw_config->slots[0] = ad1848_init("mad16 WSS", ports,
-					  hw_config->irq,
-					  dma,
-					  dma2, 0,
-					  hw_config->osp,
-					  THIS_MODULE);
-	return 1;
-
-fail:
-	release_region(hw_config->io_base + 4, 4);
-	release_region(hw_config->io_base, 4);
-	return 0;
-}
-
-static int __init probe_mad16_mpu(struct address_info *hw_config)
-{
-	unsigned char tmp;
-
-	if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
-	{
-
-#ifdef CONFIG_MAD16_OLDCARD
-
-		tmp = mad_read(MC3_PORT);
-
-		/* 
-		 * MAD16 SB base is defined by the WSS base. It cannot be changed 
-		 * alone.
-		 * Ignore configured I/O base. Use the active setting. 
-		 */
-
-		if (mad_read(MC1_PORT) & 0x20)
-			hw_config->io_base = 0x240;
-		else
-			hw_config->io_base = 0x220;
-
-		switch (hw_config->irq)
-		{
-			case 5:
-				tmp = (tmp & 0x3f) | 0x80;
-				break;
-			case 7:
-				tmp = (tmp & 0x3f);
-				break;
-			case 11:
-				tmp = (tmp & 0x3f) | 0x40;
-				break;
-			default:
-				printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n");
-				return 0;
-		}
-
-		mad_write(MC3_PORT, tmp | 0x04);
-		hw_config->driver_use_1 = SB_MIDI_ONLY;
-		if (!request_region(hw_config->io_base, 16, "soundblaster"))
-			return 0;
-		if (!sb_dsp_detect(hw_config, 0, 0, NULL)) {
-			release_region(hw_config->io_base, 16);
-			return 0;
-		}
-
-		if (mad_read(MC1_PORT) & 0x20)
-			hw_config->io_base = 0x240;
-		else
-			hw_config->io_base = 0x220;
-
-		hw_config->name = "Mad16/Mozart";
-		sb_dsp_init(hw_config, THIS_MODULE);
-		return 1;
-#else
-		/* assuming all later Mozart cards are identified as
-		 * either 82C928 or Mozart. If so, following code attempts
-		 * to set MPU register. TODO - add probing
-		 */
-
-		tmp = mad_read(MC8_PORT);
-
-		switch (hw_config->irq)
-		{
-			case 5:
-				tmp |= 0x08;
-				break;
-			case 7:
-				tmp |= 0x10;
-				break;
-			case 9:
-				tmp |= 0x18;
-				break;
-			case 10:
-				tmp |= 0x20;
-				break;
-			case 11:
-				tmp |= 0x28;
-				break;
-			default:
-				printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n");
-				return 0;
-		}
-
-		switch (hw_config->io_base)
-		{
-			case 0x300:
-				tmp |= 0x01;
-				break;
-			case 0x310:
-				tmp |= 0x03;
-				break;
-			case 0x320:
-				tmp |= 0x05;
-				break;
-			case 0x330:
-				tmp |= 0x07;
-				break;
-			default:
-				printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n");
-				return 0;
-		}
-
-		mad_write(MC8_PORT, tmp);	/* write MPU port parameters */
-		goto probe_401;
-#endif
-	}
-	tmp = mad_read(MC6_PORT) & 0x83;
-	tmp |= 0x80;		/* MPU-401 enable */
-
-	/* Set the MPU base bits */
-
-	switch (hw_config->io_base)
-	{
-		case 0x300:
-			tmp |= 0x60;
-			break;
-		case 0x310:
-			tmp |= 0x40;
-			break;
-		case 0x320:
-			tmp |= 0x20;
-			break;
-		case 0x330:
-			tmp |= 0x00;
-			break;
-		default:
-			printk(KERN_ERR "MAD16: Invalid MIDI port 0x%x\n", hw_config->io_base);
-			return 0;
-	}
-
-	/* Set the MPU IRQ bits */
-
-	switch (hw_config->irq)
-	{
-		case 5:
-			tmp |= 0x10;
-			break;
-		case 7:
-			tmp |= 0x18;
-			break;
-		case 9:
-			tmp |= 0x00;
-			break;
-		case 10:
-			tmp |= 0x08;
-			break;
-		default:
-			printk(KERN_ERR "MAD16: Invalid MIDI IRQ %d\n", hw_config->irq);
-			break;
-	}
-			
-	mad_write(MC6_PORT, tmp);	/* Write MPU401 config */
-
-#ifndef CONFIG_MAD16_OLDCARD
-probe_401:
-#endif
-	hw_config->driver_use_1 = SB_MIDI_ONLY;
-	hw_config->name = "Mad16/Mozart";
-	return probe_uart401(hw_config, THIS_MODULE);
-}
-
-static void __exit unload_mad16(struct address_info *hw_config)
-{
-	ad1848_unload(hw_config->io_base + 4,
-			hw_config->irq,
-			hw_config->dma,
-			hw_config->dma2, 0);
-	release_region(hw_config->io_base, 4);
-	sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static void __exit unload_mad16_mpu(struct address_info *hw_config)
-{
-#ifdef CONFIG_MAD16_OLDCARD
-	if (board_type < C929)	/* Early chip. No MPU support. Just SB MIDI */
-	{
-		sb_dsp_unload(hw_config, 0);
-		return;
-	}
-#endif
-
-	unload_uart401(hw_config);
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int found_mpu;
-
-static int __initdata mpu_io = 0;
-static int __initdata mpu_irq = 0;
-static int __initdata io = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1; /* Set this for modules that need it */
-static int __initdata irq = -1;
-static int __initdata cdtype = 0;
-static int __initdata cdirq = 0;
-static int __initdata cdport = 0x340;
-static int __initdata cddma = -1;
-static int __initdata opl4 = 0;
-static int __initdata joystick = 0;
-
-module_param(mpu_io, int, 0);
-module_param(mpu_irq, int, 0);
-module_param(io, int, 0);
-module_param(dma, int, 0);
-module_param(dma16, int, 0);
-module_param(irq, int, 0);
-module_param(cdtype, int, 0);
-module_param(cdirq, int, 0);
-module_param(cdport, int, 0);
-module_param(cddma, int, 0);
-module_param(opl4, int, 0);
-module_param(joystick, bool, 0);
-module_param(debug, bool, 0644);
-
-static int __initdata dma_map[2][8] =
-{
-	{0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02},
-	{0x03, -1, 0x01, 0x00, -1, -1, -1, -1}
-};
-
-static int __initdata irq_map[16] =
-{
-	0x00, -1, -1, 0x0A,
-	-1, 0x04, -1, 0x08,
-	-1, 0x10, 0x14, 0x18,
-	-1, -1, -1, -1
-};
-
-#ifdef SUPPORT_JOYSTICK
-
-static struct gameport *gameport;
-
-static int __devinit mad16_register_gameport(int io_port)
-{
-	if (!request_region(io_port, 1, "mad16 gameport")) {
-		printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port);
-		return -EBUSY;
-	}
-
-	gameport = gameport_allocate_port();
-	if (!gameport) {
-		printk(KERN_ERR "mad16: can not allocate memory for gameport\n");
-		release_region(io_port, 1);
-		return -ENOMEM;
-	}
-
-	gameport_set_name(gameport, "MAD16 Gameport");
-	gameport_set_phys(gameport, "isa%04x/gameport0", io_port);
-	gameport->io = io_port;
-
-	gameport_register_port(gameport);
-
-	return 0;
-}
-
-static inline void mad16_unregister_gameport(void)
-{
-	if (gameport) {
-		/* the gameport was initialized so we must free it up */
-		gameport_unregister_port(gameport);
-		gameport = NULL;
-		release_region(0x201, 1);
-	}
-}
-#else
-static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
-static inline void mad16_unregister_gameport(void) { }
-#endif
-
-static int __devinit init_mad16(void)
-{
-	int dmatype = 0;
-
-	printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-
-	printk(KERN_INFO "CDROM ");
-	switch (cdtype)
-	{
-		case 0x00:
-			printk("Disabled");
-			cdirq = 0;
-			break;
-		case 0x02:
-			printk("Sony CDU31A");
-			dmatype = 1;
-			if(cddma == -1) cddma = 3;
-			break;
-		case 0x04:
-			printk("Mitsumi");
-			dmatype = 0;
-			if(cddma == -1) cddma = 5;
-			break;
-		case 0x06:
-			printk("Panasonic Lasermate");
-			dmatype = 1;
-			if(cddma == -1) cddma = 3;
-			break;
-		case 0x08:
-			printk("Secondary IDE");
-			dmatype = 0;
-			if(cddma == -1) cddma = 5;
-			break;
-		case 0x0A:
-			printk("Primary IDE");
-			dmatype = 0;
-			if(cddma == -1) cddma = 5;
-			break;
-		default:
-			printk("\n");
-			printk(KERN_ERR "Invalid CDROM type\n");
-			return -EINVAL;
-	}
-
-	/*
-	 *    Build the config words
-	 */
-
-	mad16_conf = (joystick ^ 1) | cdtype;
-	mad16_cdsel = 0;
-	if (opl4)
-		mad16_cdsel |= 0x20;
-
-	if(cdtype){
-		if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1)
-		{
-			printk("\n");
-			printk(KERN_ERR "Invalid CDROM DMA\n");
-			return -EINVAL;
-		}
-		if (cddma)
-			printk(", DMA %d", cddma);
-		else
-			printk(", no DMA");
-
-		if (!cdirq)
-			printk(", no IRQ");
-		else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1)
-		{
-			printk(", invalid IRQ (disabling)");
-			cdirq = 0;
-		}
-		else printk(", IRQ %d", cdirq);
-
-		mad16_cdsel |= dma_map[dmatype][cddma];
-
-		if (cdtype < 0x08)
-		{
-			switch (cdport)
-			{
-				case 0x340:
-					mad16_cdsel |= 0x00;
-					break;
-				case 0x330:
-					mad16_cdsel |= 0x40;
-					break;
-				case 0x360:
-					mad16_cdsel |= 0x80;
-					break;
-				case 0x320:
-					mad16_cdsel |= 0xC0;
-					break;
-				default:
-					printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport);
-					return -EINVAL;
-			}
-		}
-		mad16_cdsel |= irq_map[cdirq];
-	}
-
-	printk(".\n");
-
-	cfg.io_base = io;
-	cfg.irq = irq;
-	cfg.dma = dma;
-	cfg.dma2 = dma16;
-
-	if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
-		printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
-		return -EINVAL;
-	}
-
-	if (!request_region(MC0_PORT, 12, "mad16"))
-		return -EBUSY;
-
-	if (!probe_mad16(&cfg)) {
-		release_region(MC0_PORT, 12);
-		return -ENODEV;
-	}
-
-	cfg_mpu.io_base = mpu_io;
-	cfg_mpu.irq = mpu_irq;
-
-	found_mpu = probe_mad16_mpu(&cfg_mpu);
-
-	if (joystick)
-		mad16_register_gameport(0x201);
-
-	return 0;
-}
-
-static void __exit cleanup_mad16(void)
-{
-	if (found_mpu)
-		unload_mad16_mpu(&cfg_mpu);
-	mad16_unregister_gameport();
-	unload_mad16(&cfg);
-	release_region(MC0_PORT, 12);
-}
-
-module_init(init_mad16);
-module_exit(cleanup_mad16);
-
-#ifndef MODULE
-static int __init setup_mad16(char *str)
-{
-	/* io, irq */
-	int ints[8];
-
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-
-	io	 = ints[1];
-	irq	 = ints[2];
-	dma	 = ints[3];
-	dma16	 = ints[4];
-	mpu_io	 = ints[5];
-	mpu_irq  = ints[6];
-	joystick = ints[7];
-
-	return 1;
-}
-
-__setup("mad16=", setup_mad16);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
deleted file mode 100644
index 1d98d10..0000000
--- a/sound/oss/maestro.c
+++ /dev/null
@@ -1,3686 +0,0 @@
-/*****************************************************************************
- *
- *      ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
- *
- *      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.
- *
- *	(c) Copyright 1999	 Alan Cox <alan.cox@linux.org>
- *
- *	Based heavily on SonicVibes.c:
- *      Copyright (C) 1998-1999  Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- *	Heavily modified by Zach Brown <zab@zabbo.net> based on lunch
- *	with ESS engineers.  Many thanks to Howard Kim for providing 
- *	contacts and hardware.  Honorable mention goes to Eric 
- *	Brombaugh for all sorts of things.  Best regards to the 
- *	proprietors of Hack Central for fine lodging.
- *
- *  Supported devices:
- *  /dev/dsp0-3    standard /dev/dsp device, (mostly) OSS compatible
- *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
- *
- *  Hardware Description
- *
- *	A working Maestro setup contains the Maestro chip wired to a 
- *	codec or 2.  In the Maestro we have the APUs, the ASSP, and the
- *	Wavecache.  The APUs can be though of as virtual audio routing
- *	channels.  They can take data from a number of sources and perform
- *	basic encodings of the data.  The wavecache is a storehouse for
- *	PCM data.  Typically it deals with PCI and interracts with the
- *	APUs.  The ASSP is a wacky DSP like device that ESS is loth
- *	to release docs on.  Thankfully it isn't required on the Maestro
- *	until you start doing insane things like FM emulation and surround
- *	encoding.  The codecs are almost always AC-97 compliant codecs, 
- *	but it appears that early Maestros may have had PT101 (an ESS
- *	part?) wired to them.  The only real difference in the Maestro
- *	families is external goop like docking capability, memory for
- *	the ASSP, and initialization differences.
- *
- *  Driver Operation
- *
- *	We only drive the APU/Wavecache as typical DACs and drive the
- *	mixers in the codecs.  There are 64 APUs.  We assign 6 to each
- *	/dev/dsp? device.  2 channels for output, and 4 channels for
- *	input.
- *
- *	Each APU can do a number of things, but we only really use
- *	3 basic functions.  For playback we use them to convert PCM
- *	data fetched over PCI by the wavecahche into analog data that
- *	is handed to the codec.  One APU for mono, and a pair for stereo.
- *	When in stereo, the combination of smarts in the APU and Wavecache
- *	decide which wavecache gets the left or right channel.
- *
- *	For record we still use the old overly mono system.  For each in
- *	coming channel the data comes in from the codec, through a 'input'
- *	APU, through another rate converter APU, and then into memory via
- *	the wavecache and PCI.  If its stereo, we mash it back into LRLR in
- *	software.  The pass between the 2 APUs is supposedly what requires us
- *	to have a 512 byte buffer sitting around in wavecache/memory.
- *
- *	The wavecache makes our life even more fun.  First off, it can
- *	only address the first 28 bits of PCI address space, making it
- *	useless on quite a few architectures.  Secondly, its insane.
- *	It claims to fetch from 4 regions of PCI space, each 4 meg in length.
- *	But that doesn't really work.  You can only use 1 region.  So all our
- *	allocations have to be in 4meg of each other.  Booo.  Hiss.
- *	So we have a module parameter, dsps_order, that is the order of
- *	the number of dsps to provide.  All their buffer space is allocated
- *	on open time.  The sonicvibes OSS routines we inherited really want
- *	power of 2 buffers, so we have all those next to each other, then
- *	512 byte regions for the recording wavecaches.  This ends up
- *	wasting quite a bit of memory.  The only fixes I can see would be 
- *	getting a kernel allocator that could work in zones, or figuring out
- *	just how to coerce the WP into doing what we want.
- *
- *	The indirection of the various registers means we have to spinlock
- *	nearly all register accesses.  We have the main register indirection
- *	like the wave cache, maestro registers, etc.  Then we have beasts
- *	like the APU interface that is indirect registers gotten at through
- *	the main maestro indirection.  Ouch.  We spinlock around the actual
- *	ports on a per card basis.  This means spinlock activity at each IO
- *	operation, but the only IO operation clusters are in non critical 
- *	paths and it makes the code far easier to follow.  Interrupts are
- *	blocked while holding the locks because the int handler has to
- *	get at some of them :(.  The mixer interface doesn't, however.
- *	We also have an OSS state lock that is thrown around in a few
- *	places.
- *
- *	This driver has brute force APM suspend support.  We catch suspend
- *	notifications and stop all work being done on the chip.  Any people
- *	that try between this shutdown and the real suspend operation will
- *	be put to sleep.  When we resume we restore our software state on
- *	the chip and wake up the people that were using it.  The code thats
- *	being used now is quite dirty and assumes we're on a uni-processor
- *	machine.  Much of it will need to be cleaned up for SMP ACPI or 
- *	similar.
- *
- *	We also pay attention to PCI power management now.  The driver
- *	will power down units of the chip that it knows aren't needed.
- *	The WaveProcessor and company are only powered on when people
- *	have /dev/dsp*s open.  On removal the driver will
- *	power down the maestro entirely.  There could still be
- *	trouble with BIOSen that magically change power states 
- *	themselves, but we'll see.  
- *	
- * History
- *  v0.15 - May 21 2001 - Marcus Meissner <mm@caldera.de>
- *      Ported to Linux 2.4 PCI API. Some clean ups, global devs list
- *      removed (now using pci device driver data).
- *      PM needs to be polished still. Bumped version.
- *  (still kind of v0.14) May 13 2001 - Ben Pfaff <pfaffben@msu.edu>
- *      Add support for 978 docking and basic hardware volume control
- *  (still kind of v0.14) Nov 23 - Alan Cox <alan@redhat.com>
- *	Add clocking= for people with seriously warped hardware
- *  (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- *	add __init to maestro_ac97_init() and maestro_install()
- *  (still based on v0.14) Mar 29 2000 - Zach Brown <zab@redhat.com>
- *	move to 2.3 power management interface, which
- *		required hacking some suspend/resume/check paths 
- *	make static compilation work
- *  v0.14 - Jan 28 2000 - Zach Brown <zab@redhat.com>
- *	add PCI power management through ACPI regs.
- *	we now shut down on machine reboot/halt
- *	leave scary PCI config items alone (isa stuff, mostly)
- *	enable 1921s, it seems only mine was broke.
- *	fix swapped left/right pcm dac.  har har.
- *	up bob freq, increase buffers, fix pointers at underflow
- *	silly compilation problems
- *  v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
- *	fix nec Versas?  man would that be cool.
- *  v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
- *	brown bag volume max fix..
- *  v0.11 - Nov 11 1999 - Zach Brown <zab@redhat.com>
- *	use proper stereo apu decoding, mmap/write should work.
- *	make volume sliders more useful, tweak rate calculation.
- *	fix lame 8bit format reporting bug.  duh. apm apu saving buglet also
- *	fix maestro 1 clock freq "bug", remove pt101 support
- *  v0.10 - Oct 28 1999 - Zach Brown <zab@redhat.com>
- *	aha, so, sometimes the WP writes a status word to offset 0
- *	  from one of the PCMBARs.  rearrange allocation accordingly..
- *	  cheers again to Eric for being a good hacker in investigating this.
- *	Jeroen Hoogervorst submits 7500 fix out of nowhere.  yay.  :)
- *  v0.09 - Oct 23 1999 - Zach Brown <zab@redhat.com>
- *	added APM support.
- *	re-order something such that some 2Es now work.  Magic!
- *	new codec reset routine.  made some codecs come to life.
- *	fix clear_advance, sync some control with ESS.
- *	now write to all base regs to be paranoid.
- *  v0.08 - Oct 20 1999 - Zach Brown <zab@redhat.com>
- *	Fix initial buflen bug.  I am so smart.  also smp compiling..
- *	I owe Eric yet another beer: fixed recmask, igain, 
- *	  muting, and adc sync consistency.  Go Team.
- *  v0.07 - Oct 4 1999 - Zach Brown <zab@redhat.com>
- *	tweak adc/dac, formating, and stuff to allow full duplex
- *	allocate dsps memory at open() so we can fit in the wavecache window
- *	fix wavecache braindamage.  again.  no more scribbling?
- *	fix ess 1921 codec bug on some laptops.
- *	fix dumb pci scanning bug
- *	started 2.3 cleanup, redid spinlocks, little cleanups
- *  v0.06 - Sep 20 1999 - Zach Brown <zab@redhat.com>
- *	fix wavecache thinkos.  limit to 1 /dev/dsp.
- *	eric is wearing his thinking toque this week.
- *		spotted apu mode bugs and gain ramping problem
- *	don't touch weird mixer regs, make recmask optional
- *	fixed igain inversion, defaults for mixers, clean up rec_start
- *	make mono recording work.
- *	report subsystem stuff, please send reports.
- *	littles: parallel out, amp now
- *  v0.05 - Sep 17 1999 - Zach Brown <zab@redhat.com>
- *	merged and fixed up Eric's initial recording code
- *	munged format handling to catch misuse, needs rewrite.
- *	revert ring bus init, fixup shared int, add pci busmaster setting
- *	fix mixer oss interface, fix mic mute and recmask
- *	mask off unsupported mixers, reset with all 1s, modularize defaults
- *	make sure bob is running while we need it
- *	got rid of device limit, initial minimal apm hooks
- *	pull out dead code/includes, only allow multimedia/audio maestros
- *  v0.04 - Sep 01 1999 - Zach Brown <zab@redhat.com>
- *	copied memory leak fix from sonicvibes driver
- *	different ac97 reset, play with 2.0 ac97, simplify ring bus setup
- *	bob freq code, region sanity, jitter sync fix; all from Eric 
- *
- * TODO
- *	fix bob frequency
- *	endianness
- *	do smart things with ac97 2.0 bits.
- *	dual codecs
- *	leave 54->61 open
- *
- *	it also would be fun to have a mode that would not use pci dma at all
- *	but would copy into the wavecache on board memory and use that 
- *	on architectures that don't like the maestro's pci dma ickiness.
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/reboot.h>
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-
-#include <asm/current.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "maestro.h"
-
-static struct pci_driver maestro_pci_driver;
-
-/* --------------------------------------------------------------------- */
-
-#define M_DEBUG 1
-
-#ifdef M_DEBUG
-static int debug;
-#define M_printk(args...) {if (debug) printk(args);}
-#else
-#define M_printk(x)
-#endif
-
-/* we try to setup 2^(dsps_order) /dev/dsp devices */
-static int dsps_order;
-/* whether or not we mess around with power management */
-static int use_pm=2; /* set to 1 for force */
-/* clocking for broken hardware - a few laptops seem to use a 50Khz clock
-	ie insmod with clocking=50000 or so */
-	
-static int clocking=48000;
-
-MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("ESS Maestro Driver");
-MODULE_LICENSE("GPL");
-
-#ifdef M_DEBUG
-module_param(debug, bool, 0644);
-#endif
-module_param(dsps_order, int, 0);
-module_param(use_pm, int, 0);
-module_param(clocking, int, 0);
-
-/* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.15"
-
-#ifndef PCI_VENDOR_ESS
-#define PCI_VENDOR_ESS			0x125D
-#define PCI_DEVICE_ID_ESS_ESS1968	0x1968		/* Maestro 2	*/
-#define PCI_DEVICE_ID_ESS_ESS1978      	0x1978		/* Maestro 2E	*/
-
-#define PCI_VENDOR_ESS_OLD		0x1285		/* Platform Tech, 
-						the people the maestro 
-						was bought from */
-#define PCI_DEVICE_ID_ESS_ESS0100	0x0100		/* maestro 1 */
-#endif /* PCI_VENDOR_ESS */
-
-#define ESS_CHAN_HARD		0x100
-
-/* NEC Versas ? */
-#define NEC_VERSA_SUBID1	0x80581033
-#define NEC_VERSA_SUBID2	0x803c1033
-
-
-/* changed so that I could actually find all the
-	references and fix them up.  it's a little more readable now. */
-#define ESS_FMT_STEREO	0x01
-#define ESS_FMT_16BIT	0x02
-#define ESS_FMT_MASK	0x03
-#define ESS_DAC_SHIFT	0   
-#define ESS_ADC_SHIFT	4
-
-#define ESS_STATE_MAGIC		0x125D1968
-#define ESS_CARD_MAGIC		0x19283746
-
-#define DAC_RUNNING		1
-#define ADC_RUNNING		2
-
-#define MAX_DSP_ORDER	2
-#define MAX_DSPS	(1<<MAX_DSP_ORDER)
-#define NR_DSPS		(1<<dsps_order)
-#define NR_IDRS		32
-
-#define NR_APUS		64
-#define NR_APU_REGS	16
-
-/* acpi states */
-enum {
-	ACPI_D0=0,
-	ACPI_D1,
-	ACPI_D2,
-	ACPI_D3
-};
-
-/* bits in the acpi masks */
-#define ACPI_12MHZ	( 1 << 15)
-#define ACPI_24MHZ	( 1 << 14)
-#define ACPI_978	( 1 << 13)
-#define ACPI_SPDIF	( 1 << 12)
-#define ACPI_GLUE	( 1 << 11)
-#define ACPI__10	( 1 << 10) /* reserved */
-#define ACPI_PCIINT	( 1 << 9)
-#define ACPI_HV		( 1 << 8) /* hardware volume */
-#define ACPI_GPIO	( 1 << 7)
-#define ACPI_ASSP	( 1 << 6)
-#define ACPI_SB		( 1 << 5) /* sb emul */
-#define ACPI_FM		( 1 << 4) /* fm emul */
-#define ACPI_RB		( 1 << 3) /* ringbus / aclink */
-#define ACPI_MIDI	( 1 << 2) 
-#define ACPI_GP		( 1 << 1) /* game port */
-#define ACPI_WP		( 1 << 0) /* wave processor */
-
-#define ACPI_ALL	(0xffff)
-#define ACPI_SLEEP	(~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \
-			ACPI_MIDI|ACPI_GP|ACPI_WP))
-#define ACPI_NONE	(ACPI__10)
-
-/* these masks indicate which units we care about at
-	which states */
-static u16 acpi_state_mask[] = {
-	[ACPI_D0] = ACPI_ALL,
-	[ACPI_D1] = ACPI_SLEEP,
-	[ACPI_D2] = ACPI_SLEEP,
-	[ACPI_D3] = ACPI_NONE
-};
-
-static char version[] __devinitdata =
-KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n";
-
-
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-enum card_types_t {
-	TYPE_MAESTRO,
-	TYPE_MAESTRO2,
-	TYPE_MAESTRO2E
-};
-
-static const char *card_names[]={
-	[TYPE_MAESTRO] = "ESS Maestro",
-	[TYPE_MAESTRO2] = "ESS Maestro 2",
-	[TYPE_MAESTRO2E] = "ESS Maestro 2E"
-};
-
-static int clock_freq[]={
-	[TYPE_MAESTRO] = (49152000L / 1024L),
-	[TYPE_MAESTRO2] = (50000000L / 1024L),
-	[TYPE_MAESTRO2E] = (50000000L / 1024L)
-};
-
-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-
-static struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
-
-/* --------------------------------------------------------------------- */
-
-struct ess_state {
-	unsigned int magic;
-	/* FIXME: we probably want submixers in here, but only one record pair */
-	u8 apu[6];		/* l/r output, l/r intput converters, l/r input apus */
-	u8 apu_mode[6];		/* Running mode for this APU */
-	u8 apu_pan[6];		/* Panning setup for this APU */
-	u32 apu_base[6];	/* base address for this apu */
-	struct ess_card *card;	/* Card info */
-	/* wave stuff */
-	unsigned int rateadc, ratedac;
-	unsigned char fmt, enable;
-
-	int index;
-
-	/* this locks around the oss state in the driver */
-	spinlock_t lock;
-	/* only let 1 be opening at a time */
-	struct mutex open_mutex;
-	wait_queue_head_t open_wait;
-	mode_t open_mode;
-
-	/* soundcore stuff */
-	int dev_audio;
-
-	struct dmabuf {
-		void *rawbuf;
-		unsigned buforder;
-		unsigned numfrag;
-		unsigned fragshift;
-		/* XXX zab - swptr only in here so that it can be referenced by
-			clear_advance, as far as I can tell :( */
-		unsigned hwptr, swptr;
-		unsigned total_bytes;
-		int count;
-		unsigned error; /* over/underrun */
-		wait_queue_head_t wait;
-		/* redundant, but makes calculations easier */
-		unsigned fragsize;
-		unsigned dmasize;
-		unsigned fragsamples;
-		/* OSS stuff */
-		unsigned mapped:1;
-		unsigned ready:1;	/* our oss buffers are ready to go */
-		unsigned endcleared:1;
-		unsigned ossfragshift;
-		int ossmaxfrags;
-		unsigned subdivision;
-		u16 base;		/* Offset for ptr */
-	} dma_dac, dma_adc;
-
-	/* pointer to each dsp?s piece of the apu->src buffer page */
-	void *mixbuf;
-
-};
-	
-struct ess_card {
-	unsigned int magic;
-
-	/* We keep maestro cards in a linked list */
-	struct ess_card *next;
-
-	int dev_mixer;
-
-	int card_type;
-
-	/* as most of this is static,
-		perhaps it should be a pointer to a global struct */
-	struct mixer_goo {
-		int modcnt;
-		int supported_mixers;
-		int stereo_mixers;
-		int record_sources;
-		/* the caller must guarantee arg sanity before calling these */
-/*		int (*read_mixer)(struct ess_card *card, int index);*/
-		void (*write_mixer)(struct ess_card *card,int mixer, unsigned int left,unsigned int right);
-		int (*recmask_io)(struct ess_card *card,int rw,int mask);
-		unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
-	} mix;
-	
-	int power_regs;
-		
-	int in_suspend;
-	wait_queue_head_t suspend_queue;
-
-	struct ess_state channels[MAX_DSPS];
-	u16 maestro_map[NR_IDRS];	/* Register map */
-	/* we have to store this junk so that we can come back from a
-		suspend */
-	u16 apu_map[NR_APUS][NR_APU_REGS];	/* contents of apu regs */
-
-	/* this locks around the physical registers on the card */
-	spinlock_t lock;
-
-	/* memory for this card.. wavecache limited :(*/
-	void *dmapages;
-	int dmaorder;
-
-	/* hardware resources */
-	struct pci_dev *pcidev;
-	u32 iobase;
-	u32 irq;
-
-	int bob_freq;
-	char dsps_open;
-
-	int dock_mute_vol;
-};
-
-static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val );
-
-static unsigned 
-ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static void check_suspend(struct ess_card *card);
-
-/* --------------------------------------------------------------------- */
-
-
-/*
- *	ESS Maestro AC97 codec programming interface.
- */
-	 
-static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val)
-{
-	int io = card->iobase;
-	int i;
-	/*
-	 *	Wait for the codec bus to be free 
-	 */
-
-	check_suspend(card);
-	 
-	for(i=0;i<10000;i++)
-	{
-		if(!(inb(io+ESS_AC97_INDEX)&1)) 
-			break;
-	}
-	/*
-	 *	Write the bus
-	 */ 
-	outw(val, io+ESS_AC97_DATA);
-	mdelay(1);
-	outb(cmd, io+ESS_AC97_INDEX);
-	mdelay(1);
-}
-
-static u16 maestro_ac97_get(struct ess_card *card, u8 cmd)
-{
-	int io = card->iobase;
-	int sanity=10000;
-	u16 data;
-	int i;
-	
-	check_suspend(card);
-	/*
-	 *	Wait for the codec bus to be free 
-	 */
-	 
-	for(i=0;i<10000;i++)
-	{
-		if(!(inb(io+ESS_AC97_INDEX)&1))
-			break;
-	}
-
-	outb(cmd|0x80, io+ESS_AC97_INDEX);
-	mdelay(1);
-	
-	while(inb(io+ESS_AC97_INDEX)&1)
-	{
-		sanity--;
-		if(!sanity)
-		{
-			printk(KERN_ERR "maestro: ac97 codec timeout reading 0x%x.\n",cmd);
-			return 0;
-		}
-	}
-	data=inw(io+ESS_AC97_DATA);
-	mdelay(1);
-	return data;
-}
-
-/* OSS interface to the ac97s.. */
-
-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\
-	SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\
-	SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN)
-
-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
-	SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\
-	SOUND_MASK_SPEAKER)
-
-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
-	SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
-	SOUND_MASK_PHONEIN)
-
-#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<<FOO) )
-
-/* this table has default mixer values for all OSS mixers.
-	be sure to fill it in if you add oss mixers
-	to anyone's supported mixer defines */
-
-static unsigned int mixer_defaults[SOUND_MIXER_NRDEVICES] = {
-	[SOUND_MIXER_VOLUME] =          0x3232,
-	[SOUND_MIXER_BASS] =            0x3232,
-	[SOUND_MIXER_TREBLE] =          0x3232,
-	[SOUND_MIXER_SPEAKER] =         0x3232,
-	[SOUND_MIXER_MIC] =     0x8000, /* annoying */
-	[SOUND_MIXER_LINE] =    0x3232,
-	[SOUND_MIXER_CD] =      0x3232,
-	[SOUND_MIXER_VIDEO] =   0x3232,
-	[SOUND_MIXER_LINE1] =   0x3232,
-	[SOUND_MIXER_PCM] =             0x3232,
-	[SOUND_MIXER_IGAIN] =           0x3232
-};
-	
-static struct ac97_mixer_hw {
-	unsigned char offset;
-	int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
-	[SOUND_MIXER_VOLUME]	=	{0x02,63},
-	[SOUND_MIXER_BASS]	=	{0x08,15},
-	[SOUND_MIXER_TREBLE]	=	{0x08,15},
-	[SOUND_MIXER_SPEAKER]	=	{0x0a,15},
-	[SOUND_MIXER_MIC]	=	{0x0e,31},
-	[SOUND_MIXER_LINE]	=	{0x10,31},
-	[SOUND_MIXER_CD]	=	{0x12,31},
-	[SOUND_MIXER_VIDEO]	=	{0x14,31},
-	[SOUND_MIXER_LINE1]	=	{0x16,31},
-	[SOUND_MIXER_PCM]	=	{0x18,31},
-	[SOUND_MIXER_IGAIN]	=	{0x1c,15}
-};
-
-#if 0 /* *shrug* removed simply because we never used it.
-		feel free to implement again if needed */
-
-/* reads the given OSS mixer from the ac97
-	the caller must have insured that the ac97 knows
-	about that given mixer, and should be holding a
-	spinlock for the card */
-static int ac97_read_mixer(struct ess_card *card, int mixer) 
-{
-	u16 val;
-	int ret=0;
-	struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
-	val = maestro_ac97_get(card, mh->offset);
-
-	if(AC97_STEREO_MASK & (1<<mixer)) {
-		/* nice stereo mixers .. */
-		int left,right;
-
-		left = (val >> 8)  & 0x7f;
-		right = val  & 0x7f;
-
-		if (mixer == SOUND_MIXER_IGAIN) {
-			right = (right * 100) / mh->scale;
-			left = (left * 100) / mh->scale;
-		} else {
-			right = 100 - ((right * 100) / mh->scale);
-			left = 100 - ((left * 100) / mh->scale);
-		}
-
-		ret = left | (right << 8);
-	} else if (mixer == SOUND_MIXER_SPEAKER) {
-		ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
-	} else if (mixer == SOUND_MIXER_MIC) {
-		ret = 100 - (((val & 0x1f) * 100) / mh->scale);
-	/*  the low bit is optional in the tone sliders and masking
-		it lets is avoid the 0xf 'bypass'.. */
-	} else if (mixer == SOUND_MIXER_BASS) {
-		ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
-	} else if (mixer == SOUND_MIXER_TREBLE) {
-		ret = 100 - (((val & 0xe) * 100) / mh->scale);
-	}
-
-	M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
-
-	return ret;
-}
-#endif
-
-/* write the OSS encoded volume to the given OSS encoded mixer,
-	again caller's job to make sure all is well in arg land,
-	call with spinlock held */
-	
-/* linear scale -> log */
-static unsigned char lin2log[101] = 
-{
-0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
-50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
-63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
-72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
-78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
-83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
-87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
-90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
-93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
-95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
-97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99 
-};
-
-static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
-{
-	u16 val=0;
-	struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
-	M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
-
-	if(AC97_STEREO_MASK & (1<<mixer)) {
-		/* stereo mixers, mute them if we can */
-
-		if (mixer == SOUND_MIXER_IGAIN) {
-			/* igain's slider is reversed.. */
-			right = (right * mh->scale) / 100;
-			left = (left * mh->scale) / 100;
-			if ((left == 0) && (right == 0))
-				val |= 0x8000;
-		} else if (mixer == SOUND_MIXER_PCM || mixer == SOUND_MIXER_CD) {
-			/* log conversion seems bad for them */
-			if ((left == 0) && (right == 0))
-				val = 0x8000;
-			right = ((100 - right) * mh->scale) / 100;
-			left = ((100 - left) * mh->scale) / 100;
-		} else {
-			/* log conversion for the stereo controls */
-			if((left == 0) && (right == 0))
-				val = 0x8000;
-			right = ((100 - lin2log[right]) * mh->scale) / 100;
-			left = ((100 - lin2log[left]) * mh->scale) / 100;
-		}
-
-		val |= (left << 8) | right;
-
-	} else if (mixer == SOUND_MIXER_SPEAKER) {
-		val = (((100 - left) * mh->scale) / 100) << 1;
-	} else if (mixer == SOUND_MIXER_MIC) {
-		val = maestro_ac97_get(card, mh->offset) & ~0x801f;
-		val |= (((100 - left) * mh->scale) / 100);
-	/*  the low bit is optional in the tone sliders and masking
-		it lets is avoid the 0xf 'bypass'.. */
-	} else if (mixer == SOUND_MIXER_BASS) {
-		val = maestro_ac97_get(card , mh->offset) & ~0x0f00;
-		val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
-	} else if (mixer == SOUND_MIXER_TREBLE)  {
-		val = maestro_ac97_get(card , mh->offset) & ~0x000f;
-		val |= (((100 - left) * mh->scale) / 100) & 0x000e;
-	}
-
-	maestro_ac97_set(card , mh->offset, val);
-	
-	M_printk(" -> %x\n",val);
-}
-
-/* the following tables allow us to go from 
-	OSS <-> ac97 quickly. */
-
-enum ac97_recsettings {
-	AC97_REC_MIC=0,
-	AC97_REC_CD,
-	AC97_REC_VIDEO,
-	AC97_REC_AUX,
-	AC97_REC_LINE,
-	AC97_REC_STEREO, /* combination of all enabled outputs..  */
-	AC97_REC_MONO,        /*.. or the mono equivalent */
-	AC97_REC_PHONE        
-};
-
-static unsigned int ac97_oss_mask[] = {
-	[AC97_REC_MIC] = SOUND_MASK_MIC, 
-	[AC97_REC_CD] = SOUND_MASK_CD, 
-	[AC97_REC_VIDEO] = SOUND_MASK_VIDEO, 
-	[AC97_REC_AUX] = SOUND_MASK_LINE1, 
-	[AC97_REC_LINE] = SOUND_MASK_LINE, 
-	[AC97_REC_PHONE] = SOUND_MASK_PHONEIN
-};
-
-/* indexed by bit position */
-static unsigned int ac97_oss_rm[] = {
-	[SOUND_MIXER_MIC] = AC97_REC_MIC,
-	[SOUND_MIXER_CD] = AC97_REC_CD,
-	[SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
-	[SOUND_MIXER_LINE1] = AC97_REC_AUX,
-	[SOUND_MIXER_LINE] = AC97_REC_LINE,
-	[SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
-};
-	
-/* read or write the recmask 
-	the ac97 can really have left and right recording
-	inputs independently set, but OSS doesn't seem to 
-	want us to express that to the user. 
-	the caller guarantees that we have a supported bit set,
-	and they must be holding the card's spinlock */
-static int 
-ac97_recmask_io(struct ess_card *card, int read, int mask) 
-{
-	unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ];
-
-	if (read) return val;
-
-	/* oss can have many inputs, maestro can't.  try
-		to pick the 'new' one */
-
-	if (mask != val) mask &= ~val;
-
-	val = ffs(mask) - 1; 
-	val = ac97_oss_rm[val];
-	val |= val << 8;  /* set both channels */
-
-	M_printk("maestro: setting ac97 recmask to 0x%x\n",val);
-
-	maestro_ac97_set(card,0x1a,val);
-
-	return 0;
-};
-
-/*
- *	The Maestro can be wired to a standard AC97 compliant codec
- *	(see www.intel.com for the pdf's on this), or to a PT101 codec
- *	which appears to be the ES1918 (data sheet on the esstech.com.tw site)
- *
- *	The PT101 setup is untested.
- */
- 
-static u16 __init maestro_ac97_init(struct ess_card *card)
-{
-	u16 vend1, vend2, caps;
-
-	card->mix.supported_mixers = AC97_SUPPORTED_MASK;
-	card->mix.stereo_mixers = AC97_STEREO_MASK;
-	card->mix.record_sources = AC97_RECORD_MASK;
-/*	card->mix.read_mixer = ac97_read_mixer;*/
-	card->mix.write_mixer = ac97_write_mixer;
-	card->mix.recmask_io = ac97_recmask_io;
-
-	vend1 = maestro_ac97_get(card, 0x7c);
-	vend2 = maestro_ac97_get(card, 0x7e);
-
-	caps = maestro_ac97_get(card, 0x00);
-
-	printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n",
-		vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf);
-
-	if (! (caps & 0x4) ) {
-		/* no bass/treble nobs */
-		card->mix.supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
-	}
-
-	/* XXX endianness, dork head. */
-	/* vendor specifc bits.. */
-	switch ((long)(vend1 << 16) | vend2) {
-	case 0x545200ff:	/* TriTech */
-		/* no idea what this does */
-		maestro_ac97_set(card,0x2a,0x0001);
-		maestro_ac97_set(card,0x2c,0x0000);
-		maestro_ac97_set(card,0x2c,0xffff);
-		break;
-#if 0	/* i thought the problems I was seeing were with
-	the 1921, but apparently they were with the pci board
-	it was on, so this code is commented out.
-	 lets see if this holds true. */
-	case 0x83847609:	/* ESS 1921 */
-		/* writing to 0xe (mic) or 0x1a (recmask) seems
-			to hang this codec */
-		card->mix.supported_mixers &= ~(SOUND_MASK_MIC);
-		card->mix.record_sources = 0;
-		card->mix.recmask_io = NULL;
-#if 0	/* don't ask.  I have yet to see what these actually do. */
-		maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
-		udelay(20);
-		maestro_ac97_set(card,0x78,0x3002);
-		udelay(20);
-		maestro_ac97_set(card,0x78,0x3802);
-		udelay(20);
-#endif
-		break;
-#endif
-	default: break;
-	}
-
-	maestro_ac97_set(card, 0x1E, 0x0404);
-	/* null misc stuff */
-	maestro_ac97_set(card, 0x20, 0x0000);
-
-	return 0;
-}
-
-#if 0  /* there has been 1 person on the planet with a pt101 that we
-	know of.  If they care, they can put this back in :) */
-static u16 maestro_pt101_init(struct ess_card *card,int iobase)
-{
-	printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
-	/* who knows.. */
-	maestro_ac97_set(iobase, 0x2A, 0x0001);
-	maestro_ac97_set(iobase, 0x2C, 0x0000);
-	maestro_ac97_set(iobase, 0x2C, 0xFFFF);
-	maestro_ac97_set(iobase, 0x10, 0x9F1F);
-	maestro_ac97_set(iobase, 0x12, 0x0808);
-	maestro_ac97_set(iobase, 0x14, 0x9F1F);
-	maestro_ac97_set(iobase, 0x16, 0x9F1F);
-	maestro_ac97_set(iobase, 0x18, 0x0404);
-	maestro_ac97_set(iobase, 0x1A, 0x0000);
-	maestro_ac97_set(iobase, 0x1C, 0x0000);
-	maestro_ac97_set(iobase, 0x02, 0x0404);
-	maestro_ac97_set(iobase, 0x04, 0x0808);
-	maestro_ac97_set(iobase, 0x0C, 0x801F);
-	maestro_ac97_set(iobase, 0x0E, 0x801F);
-	return 0;
-}
-#endif
-
-/* this is very magic, and very slow.. */
-static void 
-maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
-{
-	u16 save_68;
-	u16 w;
-	u32 vend;
-
-	outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
-	outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
-	outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
-
-	/* reset the first codec */
-	outw(0x0000,  ioaddr+0x36);
-	save_68 = inw(ioaddr+0x68);
-	pci_read_config_word(pcidev, 0x58, &w);	/* something magical with gpio and bus arb. */
-	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);
-	if( w & 0x1)
-		save_68 |= 0x10;
-	outw(0xfffe, ioaddr + 0x64);	/* tickly gpio 0.. */
-	outw(0x0001, ioaddr + 0x68);
-	outw(0x0000, ioaddr + 0x60);
-	udelay(20);
-	outw(0x0001, ioaddr + 0x60);
-	mdelay(20);
-
-	outw(save_68 | 0x1, ioaddr + 0x68);	/* now restore .. */
-	outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38);
-	outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a);
-	outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c);
-
-	/* now the second codec */
-	outw(0x0000,  ioaddr+0x36);
-	outw(0xfff7, ioaddr + 0x64);
-	save_68 = inw(ioaddr+0x68);
-	outw(0x0009, ioaddr + 0x68);
-	outw(0x0001, ioaddr + 0x60);
-	udelay(20);
-	outw(0x0009, ioaddr + 0x60);
-	mdelay(500);	/* .. ouch.. */
-	outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
-	outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
-	outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
-
-#if 0 /* the loop here needs to be much better if we want it.. */
-	M_printk("trying software reset\n");
-	/* try and do a software reset */
-	outb(0x80|0x7c, ioaddr + 0x30);
-	for (w=0; ; w++) {
-		if ((inw(ioaddr+ 0x30) & 1) == 0) {
-			if(inb(ioaddr + 0x32) !=0) break;
-
-			outb(0x80|0x7d, ioaddr + 0x30);
-			if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
-			outb(0x80|0x7f, ioaddr + 0x30);
-			if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
-		}
-
-		if( w > 10000) {
-			outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37);  /* do a software reset */
-			mdelay(500); /* oh my.. */
-			outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37);  
-			udelay(1);
-			outw( 0x80, ioaddr+0x30);
-			for(w = 0 ; w < 10000; w++) {
-				if((inw(ioaddr + 0x30) & 1) ==0) break;
-			}
-		}
-	}
-#endif
-	if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {
-		/* turn on external amp? */
-		outw(0xf9ff, ioaddr + 0x64);
-		outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
-		outw(0x0209, ioaddr + 0x60);
-	}
-
-	/* Turn on the 978 docking chip.
-	   First frob the "master output enable" bit,
-	   then set most of the playback volume control registers to max. */
-	outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);
-	outb(0xff, ioaddr+0xc3);
-	outb(0xff, ioaddr+0xc4);
-	outb(0xff, ioaddr+0xc6);
-	outb(0xff, ioaddr+0xc8);
-	outb(0x3f, ioaddr+0xcf);
-	outb(0x3f, ioaddr+0xd0);
-}
-/*
- *	Indirect register access. Not all registers are readable so we
- *	need to keep register state ourselves
- */
- 
-#define WRITEABLE_MAP	0xEFFFFF
-#define READABLE_MAP	0x64003F
-
-/*
- *	The Maestro engineers were a little indirection happy. These indirected
- *	registers themselves include indirect registers at another layer
- */
-
-static void __maestro_write(struct ess_card *card, u16 reg, u16 data)
-{
-	long ioaddr = card->iobase;
-
-	outw(reg, ioaddr+0x02);
-	outw(data, ioaddr+0x00);
-	if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg);
-	else card->maestro_map[reg]=data;
-
-}
- 
-static void maestro_write(struct ess_state *s, u16 reg, u16 data)
-{
-	unsigned long flags;
-
-	check_suspend(s->card);
-	spin_lock_irqsave(&s->card->lock,flags);
-
-	__maestro_write(s->card,reg,data);
-
-	spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 __maestro_read(struct ess_card *card, u16 reg)
-{
-	long ioaddr = card->iobase;
-
-	outw(reg, ioaddr+0x02);
-	return card->maestro_map[reg]=inw(ioaddr+0x00);
-}
-
-static u16 maestro_read(struct ess_state *s, u16 reg)
-{
-	if(READABLE_MAP & (1<<reg))
-	{
-		unsigned long flags;
-		check_suspend(s->card);
-		spin_lock_irqsave(&s->card->lock,flags);
-
-		__maestro_read(s->card,reg);
-
-		spin_unlock_irqrestore(&s->card->lock,flags);
-	}
-	return s->card->maestro_map[reg];
-}
-
-/*
- *	These routines handle accessing the second level indirections to the
- *	wave ram.
- */
-
-/*
- *	The register names are the ones ESS uses (see 104T31.ZIP)
- */
- 
-#define IDR0_DATA_PORT		0x00
-#define IDR1_CRAM_POINTER	0x01
-#define IDR2_CRAM_DATA		0x02
-#define IDR3_WAVE_DATA		0x03
-#define IDR4_WAVE_PTR_LOW	0x04
-#define IDR5_WAVE_PTR_HI	0x05
-#define IDR6_TIMER_CTRL		0x06
-#define IDR7_WAVE_ROMRAM	0x07
-
-static void apu_index_set(struct ess_card *card, u16 index)
-{
-	int i;
-	__maestro_write(card, IDR1_CRAM_POINTER, index);
-	for(i=0;i<1000;i++)
-		if(__maestro_read(card, IDR1_CRAM_POINTER)==index)
-			return;
-	printk(KERN_WARNING "maestro: APU register select failed.\n");
-}
-
-static void apu_data_set(struct ess_card *card, u16 data)
-{
-	int i;
-	for(i=0;i<1000;i++)
-	{
-		if(__maestro_read(card, IDR0_DATA_PORT)==data)
-			return;
-		__maestro_write(card, IDR0_DATA_PORT, data);
-	}
-}
-
-/*
- *	This is the public interface for APU manipulation. It handles the
- *	interlock to avoid two APU writes in parallel etc. Don't diddle
- *	directly with the stuff above.
- */
-
-static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data)
-{
-	unsigned long flags;
-	
-	check_suspend(s->card);
-
-	if(channel&ESS_CHAN_HARD)
-		channel&=~ESS_CHAN_HARD;
-	else
-	{
-		if(channel>5)
-			printk("BAD CHANNEL %d.\n",channel);
-		else
-			channel = s->apu[channel];
-		/* store based on real hardware apu/reg */
-		s->card->apu_map[channel][reg]=data;
-	}
-	reg|=(channel<<4);
-	
-	/* hooray for double indirection!! */
-	spin_lock_irqsave(&s->card->lock,flags);
-
-	apu_index_set(s->card, reg);
-	apu_data_set(s->card, data);
-
-	spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg)
-{
-	unsigned long flags;
-	u16 v;
-	
-	check_suspend(s->card);
-
-	if(channel&ESS_CHAN_HARD)
-		channel&=~ESS_CHAN_HARD;
-	else
-		channel = s->apu[channel];
-
-	reg|=(channel<<4);
-	
-	spin_lock_irqsave(&s->card->lock,flags);
-
-	apu_index_set(s->card, reg);
-	v=__maestro_read(s->card, IDR0_DATA_PORT);
-
-	spin_unlock_irqrestore(&s->card->lock,flags);
-	return v;
-}
-
-
-/*
- *	The wavecache buffers between the APUs and
- *	pci bus mastering
- */
- 
-static void wave_set_register(struct ess_state *s, u16 reg, u16 value)
-{
-	long ioaddr = s->card->iobase;
-	unsigned long flags;
-	check_suspend(s->card);
-	
-	spin_lock_irqsave(&s->card->lock,flags);
-
-	outw(reg, ioaddr+0x10);
-	outw(value, ioaddr+0x12);
-
-	spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 wave_get_register(struct ess_state *s, u16 reg)
-{
-	long ioaddr = s->card->iobase;
-	unsigned long flags;
-	u16 value;
-	check_suspend(s->card);
-	
-	spin_lock_irqsave(&s->card->lock,flags);
-	outw(reg, ioaddr+0x10);
-	value=inw(ioaddr+0x12);
-	spin_unlock_irqrestore(&s->card->lock,flags);
-	
-	return value;
-}
-
-static void sound_reset(int ioaddr)
-{
-	outw(0x2000, 0x18+ioaddr);
-	udelay(1);
-	outw(0x0000, 0x18+ioaddr);
-	udelay(1);
-}
-
-/* sets the play formats of these apus, should be passed the already shifted format */
-static void set_apu_fmt(struct ess_state *s, int apu, int mode)
-{
-	int apu_fmt = 0x10;
-
-	if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20; 
-	if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10; 
-	s->apu_mode[apu]   = apu_fmt;
-	s->apu_mode[apu+1] = apu_fmt;
-}
-
-/* this only fixes the output apu mode to be later set by start_dac and
-	company.  output apu modes are set in ess_rec_setup */
-static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
-{
-	s->fmt = (s->fmt & mask) | data;
-	set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
-}
-
-/* this is off by a little bit.. */
-static u32 compute_rate(struct ess_state *s, u32 freq)
-{
-	u32 clock = clock_freq[s->card->card_type];     
-
-	freq = (freq * clocking)/48000;
-	
-	if (freq == 48000) 
-		return 0x10000;
-
-	return ((freq / clock) <<16 )+  
-		(((freq % clock) << 16) / clock);
-}
-
-static void set_dac_rate(struct ess_state *s, unsigned int rate)
-{
-	u32 freq;
-	int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 4000)
-		rate = 4000;
-
-	s->ratedac = rate;
-
-	if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
-		rate >>= 1;
-
-/*	M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
-
-	freq = compute_rate(s, rate);
-	
-	/* Load the frequency, turn on 6dB */
-	apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
-		( ((freq&0xFF)<<8)|0x10 ));
-	apu_set_register(s, 0, 3, freq>>8);
-	apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)|
-		( ((freq&0xFF)<<8)|0x10 ));
-	apu_set_register(s, 1, 3, freq>>8);
-}
-
-static void set_adc_rate(struct ess_state *s, unsigned rate)
-{
-	u32 freq;
-
-	/* Sample Rate conversion APUs don't like 0x10000 for their rate */
-	if (rate > 47999)
-		rate = 47999;
-	if (rate < 4000)
-		rate = 4000;
-
-	s->rateadc = rate;
-
-	freq = compute_rate(s, rate);
-	
-	/* Load the frequency, turn on 6dB */
-	apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
-		( ((freq&0xFF)<<8)|0x10 ));
-	apu_set_register(s, 2, 3, freq>>8);
-	apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)|
-		( ((freq&0xFF)<<8)|0x10 ));
-	apu_set_register(s, 3, 3, freq>>8);
-
-	/* fix mixer rate at 48khz.  and its _must_ be 0x10000. */
-	freq = 0x10000;
-
-	apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)|
-		( ((freq&0xFF)<<8)|0x10 ));
-	apu_set_register(s, 4, 3, freq>>8);
-	apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)|
-		( ((freq&0xFF)<<8)|0x10 ));
-	apu_set_register(s, 5, 3, freq>>8);
-}
-
-/* Stop our host of recording apus */
-static inline void stop_adc(struct ess_state *s)
-{
-	/* XXX lets hope we don't have to lock around this */
-	if (! (s->enable & ADC_RUNNING)) return;
-
-	s->enable &= ~ADC_RUNNING;
-	apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F);
-	apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F);
-	apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F);
-	apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F);
-}	
-
-/* stop output apus */
-static void stop_dac(struct ess_state *s)
-{
-	/* XXX have to lock around this? */
-	if (! (s->enable & DAC_RUNNING)) return;
-
-	s->enable &= ~DAC_RUNNING;
-	apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F);
-	apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F);
-}	
-
-static void start_dac(struct ess_state *s)
-{
-	/* XXX locks? */
-	if (	(s->dma_dac.mapped || s->dma_dac.count > 0) && 
-		s->dma_dac.ready &&
-		(! (s->enable & DAC_RUNNING)) ) {
-
-		s->enable |= DAC_RUNNING;
-
-		apu_set_register(s, 0, 0, 
-			(apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]);
-
-		if((s->fmt >> ESS_DAC_SHIFT)  & ESS_FMT_STEREO) 
-			apu_set_register(s, 1, 0, 
-				(apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]);
-	}
-}	
-
-static void start_adc(struct ess_state *s)
-{
-	/* XXX locks? */
-	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
-	    && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) {
-
-		s->enable |= ADC_RUNNING;
-		apu_set_register(s, 2, 0, 
-			(apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]);
-		apu_set_register(s, 4, 0, 
-			(apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]);
-
-		if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
-			apu_set_register(s, 3, 0, 
-				(apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]);
-			apu_set_register(s, 5, 0, 
-				(apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]);
-		}
-			
-	}
-}	
-
-
-/*
- *	Native play back driver 
- */
-
-/* the mode passed should be already shifted and masked */
-static void 
-ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
-{
-	u32 pa;
-	u32 tmpval;
-	int high_apu = 0;
-	int channel;
-
-	M_printk("mode=%d rate=%d buf=%p len=%d.\n",
-		mode, rate, buffer, size);
-		
-	/* all maestro sizes are in 16bit words */
-	size >>=1;
-
-	if(mode&ESS_FMT_STEREO) {
-		high_apu++;
-		/* only 16/stereo gets size divided */
-		if(mode&ESS_FMT_16BIT)
-			size>>=1;
-	}
-	
-	for(channel=0; channel <= high_apu; channel++)
-	{
-		pa = virt_to_bus(buffer);
-
-		/* set the wavecache control reg */
-		tmpval = (pa - 0x10) & 0xFFF8;
-		if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
-		if(mode & ESS_FMT_STEREO) tmpval |= 2;
-		ess->apu_base[channel]=tmpval;
-		wave_set_register(ess, ess->apu[channel]<<3, tmpval);
-		
-		pa -= virt_to_bus(ess->card->dmapages);
-		pa>>=1; /* words */
-		
-		/* base offset of dma calcs when reading the pointer
-			on the left one */
-		if(!channel) ess->dma_dac.base = pa&0xFFFF;
-		
-		pa|=0x00400000;			/* System RAM */
-
-		/* XXX the 16bit here might not be needed.. */
-		if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
-			if(channel) 
-				pa|=0x00800000;			/* Stereo */
-			pa>>=1;
-		}
-			
-/* XXX think about endianess when writing these registers */
-		M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
-		/* start of sample */
-		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
-		apu_set_register(ess, channel, 5, pa&0xFFFF);
-		/* sample end */
-		apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
-		/* setting loop len == sample len */
-		apu_set_register(ess, channel, 7, size);
-		
-		/* clear effects/env.. */
-		apu_set_register(ess, channel, 8, 0x0000);
-		/* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */
-		apu_set_register(ess, channel, 9, 0xD000);
-
-		/* clear routing stuff */
-		apu_set_register(ess, channel, 11, 0x0000);
-		/* dma on, no envelopes, filter to all 1s) */
-		apu_set_register(ess, channel, 0, 0x400F);
-		
-		if(mode&ESS_FMT_16BIT)
-			ess->apu_mode[channel]=0x10;
-		else
-			ess->apu_mode[channel]=0x30;
-
-		if(mode&ESS_FMT_STEREO) {
-			/* set panning: left or right */
-			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10));
-			ess->apu_mode[channel] += 0x10;
-		} else
-			apu_set_register(ess, channel, 10, 0x8F08);
-	}
-	
-	/* clear WP interrupts */
-	outw(1, ess->card->iobase+0x04);
-	/* enable WP ints */
-	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
-
-	/* go team! */
-	set_dac_rate(ess,rate);
-	start_dac(ess);
-}
-
-/*
- *	Native record driver 
- */
-
-/* again, passed mode is alrady shifted/masked */
-static void 
-ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
-{
-	int apu_step = 2;
-	int channel;
-
-	M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n",
-		mode, rate, buffer, size);
-		
-	/* all maestro sizes are in 16bit words */
-	size >>=1;
-
-	/* we're given the full size of the buffer, but
-	in stereo each channel will only use its half */
-	if(mode&ESS_FMT_STEREO) {
-		size >>=1; 
-		apu_step = 1;
-	}
-	
-	/* APU assignments: 2 = mono/left SRC
-	                    3 = right SRC
-	                    4 = mono/left Input Mixer
-	                    5 = right Input Mixer */
-	for(channel=2;channel<6;channel+=apu_step)
-	{
-		int i;
-		int bsize, route;
-		u32 pa;
-		u32 tmpval;
-
-		/* data seems to flow from the codec, through an apu into
-			the 'mixbuf' bit of page, then through the SRC apu
-			and out to the real 'buffer'.  ok.  sure.  */
-		
-		if(channel & 0x04) {
-			/* ok, we're an input mixer going from adc
-				through the mixbuf to the other apus */
-
-			if(!(channel & 0x01)) { 
-				pa = virt_to_bus(ess->mixbuf);
-			} else {
-				pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4));
-			}
-
-			/* we source from a 'magic' apu */
-			bsize = PAGE_SIZE >> 5;	/* half of this channels alloc, in words */
-			route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */
-			ess->apu_mode[channel] = 0x90;  /* Input Mixer */
-
-		} else {  
-			/* we're a rate converter taking
-				input from the input apus and outputing it to
-				system memory */
-			if(!(channel & 0x01))  {
-				pa = virt_to_bus(buffer);
-			} else {
-				/* right channel records its split half.
-				*2 accommodates for rampant shifting earlier */
-				pa = virt_to_bus(buffer + size*2);
-			}
-
-			ess->apu_mode[channel] = 0xB0;  /* Sample Rate Converter */
-
-			bsize = size; 
-			/* get input from inputing apu */
-			route = channel + 2;
-		}
-
-		M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel);
-		
-		/* set the wavecache control reg */
-		tmpval = (pa - 0x10) & 0xFFF8;
-		ess->apu_base[channel]=tmpval;
-		wave_set_register(ess, ess->apu[channel]<<3, tmpval);
-		
-		pa -= virt_to_bus(ess->card->dmapages);
-		pa>>=1; /* words */
-		
-		/* base offset of dma calcs when reading the pointer
-			on this left one */
-		if(channel==2) ess->dma_adc.base = pa&0xFFFF;
-
-		pa|=0x00400000;			/* bit 22 -> System RAM */
-
-		M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n", 
-			ess->apu[channel], pa, bsize, route);
-		
-		/* Begin loading the APU */		
-		for(i=0;i<15;i++)		/* clear all PBRs */
-			apu_set_register(ess, channel, i, 0x0000);
-			
-		apu_set_register(ess, channel, 0, 0x400F);
-
-		/* need to enable subgroups.. and we should probably
-			have different groups for different /dev/dsps..  */
- 		apu_set_register(ess, channel, 2, 0x8);
-				
-		/* Load the buffer into the wave engine */
-		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
-		/* XXX reg is little endian.. */
-		apu_set_register(ess, channel, 5, pa&0xFFFF);
-		apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF);
-		apu_set_register(ess, channel, 7, bsize);
-				
-		/* clear effects/env.. */
-		apu_set_register(ess, channel, 8, 0x00F0);
-		
-		/* amplitude now?  sure.  why not.  */
-		apu_set_register(ess, channel, 9, 0x0000);
-
-		/* set filter tune, radius, polar pan */
-		apu_set_register(ess, channel, 10, 0x8F08);
-
-		/* route input */
-		apu_set_register(ess, channel, 11, route);
-	}
-	
-	/* clear WP interrupts */
-	outw(1, ess->card->iobase+0x04);
-	/* enable WP ints */
-	outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
-
-	/* let 'er rip */
-	set_adc_rate(ess,rate);
-	start_adc(ess);
-}
-/* --------------------------------------------------------------------- */
-
-static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count)
-{
-	M_printk("set_dmaa??\n");
-}
-
-static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count)
-{
-	M_printk("set_dmac??\n");
-}
-
-/* Playback pointer */
-static inline unsigned get_dmaa(struct ess_state *s)
-{
-	int offset;
-
-	offset = apu_get_register(s,0,5);
-
-/*	M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */
-	
-	offset-=s->dma_dac.base;
-
-	return (offset&0xFFFE)<<1; /* hardware is in words */
-}
-
-/* Record pointer */
-static inline unsigned get_dmac(struct ess_state *s)
-{
-	int offset;
-
-	offset = apu_get_register(s,2,5);
-
-/*	M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */
-	
-	/* The offset is an address not a position relative to base */
-	offset-=s->dma_adc.base;
-	
-	return (offset&0xFFFE)<<1; /* hardware is in words */
-}
-
-/*
- *	Meet Bob, the timer...
- */
-
-static irqreturn_t ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-static void stop_bob(struct ess_state *s)
-{
-	/* Mask IDR 11,17 */
-	maestro_write(s,  0x11, maestro_read(s, 0x11)&~1);
-	maestro_write(s,  0x17, maestro_read(s, 0x17)&~1);
-}
-
-/* eventually we could be clever and limit bob ints
-	to the frequency at which our smallest duration
-	chunks may expire */
-#define ESS_SYSCLK	50000000
-static void start_bob(struct ess_state *s)
-{
-	int prescale;
-	int divide;
-	
-	/* XXX make freq selector much smarter, see calc_bob_rate */
-	int freq = 200; 
-	
-	/* compute ideal interrupt frequency for buffer size & play rate */
-	/* first, find best prescaler value to match freq */
-	for(prescale=5;prescale<12;prescale++)
-		if(freq > (ESS_SYSCLK>>(prescale+9)))
-			break;
-			
-	/* next, back off prescaler whilst getting divider into optimum range */
-	divide=1;
-	while((prescale > 5) && (divide<32))
-	{
-		prescale--;
-		divide <<=1;
-	}
-	divide>>=1;
-	
-	/* now fine-tune the divider for best match */
-	for(;divide<31;divide++)
-		if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1)))
-			break;
-	
-	/* divide = 0 is illegal, but don't let prescale = 4! */
-	if(divide == 0)
-	{
-		divide++;
-		if(prescale>5)
-			prescale--;
-	}
-
-	maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */
-	
-	/* Now set IDR 11/17 */
-	maestro_write(s, 0x11, maestro_read(s, 0x11)|1);
-	maestro_write(s, 0x17, maestro_read(s, 0x17)|1);
-}
-/* --------------------------------------------------------------------- */
-
-/* this quickly calculates the frequency needed for bob
-	and sets it if its different than what bob is
-	currently running at.  its called often so 
-	needs to be fairly quick. */
-#define BOB_MIN 50
-#define BOB_MAX 400
-static void calc_bob_rate(struct ess_state *s) {
-#if 0 /* this thing tries to set the frequency of bob such that
-	there are 2 interrupts / buffer walked by the dac/adc.  That
-	is probably very wrong for people who actually care about 
-	mid buffer positioning.  it should be calculated as bytes/interrupt
-	and that needs to be decided :)  so for now just use the static 150
-	in start_bob.*/
-
-	unsigned int dac_rate=2,adc_rate=1,newrate;
-	static int israte=-1;
-
-	if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN;
-	else  {
-		dac_rate =	(2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
-				(s->dma_dac.fragsize) ;
-	}
-		
-	if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN;
-	else {
-		adc_rate =	(2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
-				(s->dma_adc.fragsize) ;
-	}
-
-	if(dac_rate > adc_rate) newrate = adc_rate;
-	else newrate=dac_rate;
-
-	if(newrate > BOB_MAX) newrate = BOB_MAX;
-	else {
-		if(newrate < BOB_MIN) 
-			newrate = BOB_MIN;
-	}
-
-	if( israte != newrate) {
-		printk("dac: %d  adc: %d rate: %d\n",dac_rate,adc_rate,israte);
-		israte=newrate;
-	}
-#endif
-
-}
-
-static int 
-prog_dmabuf(struct ess_state *s, unsigned rec)
-{
-	struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
-	unsigned rate = rec ? s->rateadc : s->ratedac;
-	unsigned bytepersec;
-	unsigned bufs;
-	unsigned char fmt;
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	fmt = s->fmt;
-	if (rec) {
-		stop_adc(s);
-		fmt >>= ESS_ADC_SHIFT;
-	} else {
-		stop_dac(s);
-		fmt >>= ESS_DAC_SHIFT;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	fmt &= ESS_FMT_MASK;
-
-	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
-	/* this algorithm is a little nuts.. where did /1000 come from? */
-	bytepersec = rate << sample_shift[fmt];
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytepersec)
-			db->fragshift = ld2(bytepersec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3; 
-	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-	db->fragsamples = db->fragsize >> sample_shift[fmt];
-	db->dmasize = db->numfrag << db->fragshift;
-
-	M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
-
-	memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
-
-	spin_lock_irqsave(&s->lock, flags);
-	if (rec) 
-		ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
-	else 
-		ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
-
-	spin_unlock_irqrestore(&s->lock, flags);
-	db->ready = 1;
-
-	return 0;
-}
-
-static __inline__ void 
-clear_advance(struct ess_state *s)
-{
-	unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
-	
-	unsigned char *buf = s->dma_dac.rawbuf;
-	unsigned bsize = s->dma_dac.dmasize;
-	unsigned bptr = s->dma_dac.swptr;
-	unsigned len = s->dma_dac.fragsize;
-	
-	if (bptr + len > bsize) {
-		unsigned x = bsize - bptr;
-		memset(buf + bptr, c, x);
-		/* account for wrapping? */
-		bptr = 0;
-		len -= x;
-	}
-	memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void 
-ess_update_ptr(struct ess_state *s)
-{
-	unsigned hwptr;
-	int diff;
-
-	/* update ADC pointer */
-	if (s->dma_adc.ready) {
-		/* oh boy should this all be re-written.  everything in the current code paths think
-		that the various counters/pointers are expressed in bytes to the user but we have
-		two apus doing stereo stuff so we fix it up here.. it propagates to all the various
-		counters from here.  */
-		if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
-			hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize;
-		} else {
-			hwptr = get_dmac(s) % s->dma_adc.dmasize;
-		}
-		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
-		s->dma_adc.hwptr = hwptr;
-		s->dma_adc.total_bytes += diff;
-		s->dma_adc.count += diff;
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
-			wake_up(&s->dma_adc.wait);
-		if (!s->dma_adc.mapped) {
-			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-				/* FILL ME 
-				wrindir(s, SV_CIENABLE, s->enable); */
-				stop_adc(s); 
-				/* brute force everyone back in sync, sigh */
-				s->dma_adc.count = 0;
-				s->dma_adc.swptr = 0;
-				s->dma_adc.hwptr = 0;
-				s->dma_adc.error++;
-			}
-		}
-	}
-	/* update DAC pointer */
-	if (s->dma_dac.ready) {
-		hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
-		/* the apu only reports the length it has seen, not the
-			length of the memory that has been used (the WP
-			knows that) */
-		if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
-			hwptr<<=1;
-
-		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-/*		M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
-		s->dma_dac.hwptr = hwptr;
-		s->dma_dac.total_bytes += diff;
-		if (s->dma_dac.mapped) {
-			s->dma_dac.count += diff;
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
-				wake_up(&s->dma_dac.wait);
-			}
-		} else {
-			s->dma_dac.count -= diff;
-/*			M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
-			if (s->dma_dac.count <= 0) {
-				M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count, 
-					hwptr, s->dma_dac.swptr);
-				/* FILL ME 
-				wrindir(s, SV_CIENABLE, s->enable); */
-				/* XXX how on earth can calling this with the lock held work.. */
-				stop_dac(s);
-				/* brute force everyone back in sync, sigh */
-				s->dma_dac.count = 0; 
-				s->dma_dac.swptr = hwptr; 
-				s->dma_dac.error++;
-			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
-				clear_advance(s);
-				s->dma_dac.endcleared = 1;
-			}
-			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
-				wake_up(&s->dma_dac.wait);
-/*				printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr, 
-					hwptr);*/
-			}
-		}
-	}
-}
-
-static irqreturn_t
-ess_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct ess_state *s;
-        struct ess_card *c = (struct ess_card *)dev_id;
-	int i;
-	u32 event;
-
-	if ( ! (event = inb(c->iobase+0x1A)) )
-		return IRQ_NONE;
-
-	outw(inw(c->iobase+4)&1, c->iobase+4);
-
-/*	M_printk("maestro int: %x\n",event);*/
-	if(event&(1<<6))
-	{
-		int x;
-		enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt;
-		int volume;
-
-		/* Figure out which volume control button was pushed,
-		   based on differences from the default register
-		   values. */
-		x = inb(c->iobase+0x1c);
-		if (x&1) vol_evt = MUTE_EVT;
-		else if (((x>>1)&7) > 4) vol_evt = UP_EVT;
-		else vol_evt = DOWN_EVT;
-
-		/* Reset the volume control registers. */
-		outb(0x88, c->iobase+0x1c);
-		outb(0x88, c->iobase+0x1d);
-		outb(0x88, c->iobase+0x1e);
-		outb(0x88, c->iobase+0x1f);
-
-		/* Deal with the button press in a hammer-handed
-		   manner by adjusting the master mixer volume. */
-		volume = c->mix.mixer_state[0] & 0xff;
-		if (vol_evt == UP_EVT) {
-			volume += 5;
-			if (volume > 100)
-				volume = 100;
-		}
-		else if (vol_evt == DOWN_EVT) {
-			volume -= 5;
-			if (volume < 0)
-				volume = 0;
-		} else {
-			/* vol_evt == MUTE_EVT */
-			if (volume == 0)
-				volume = c->dock_mute_vol;
-			else {
-				c->dock_mute_vol = volume;
-				volume = 0;
-			}
-		}
-		set_mixer (c, 0, (volume << 8) | volume);
-	}
-
-	/* Ack all the interrupts. */
-	outb(0xFF, c->iobase+0x1A);
-		
-	/*
-	 *	Update the pointers for all APU's we are running.
-	 */
-	for(i=0;i<NR_DSPS;i++)
-	{
-		s=&c->channels[i];
-		if(s->dev_audio == -1)
-			break;
-		spin_lock(&s->lock);
-		ess_update_ptr(s);
-		spin_unlock(&s->lock);
-	}
-	return IRQ_HANDLED;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n";
-
-#define VALIDATE_MAGIC(FOO,MAG)                         \
-({                                                \
-	if (!(FOO) || (FOO)->magic != MAG) { \
-		printk(invalid_magic,__FUNCTION__);            \
-		return -ENXIO;                    \
-	}                                         \
-})
-
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC)
-
-static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val ) 
-{
-	unsigned int left,right;
-	/* cleanse input a little */
-	right = ((val >> 8)  & 0xff) ;
-	left = (val  & 0xff) ;
-
-	if(right > 100) right = 100;
-	if(left > 100) left = 100;
-
-	card->mix.mixer_state[mixer]=(right << 8) | left;
-	card->mix.write_mixer(card,mixer,left,right);
-}
-
-static void
-mixer_push_state(struct ess_card *card)
-{
-	int i;
-	for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
-		if( ! supported_mixer(card,i)) continue;
-
-		set_mixer(card,i,card->mix.mixer_state[i]);
-	}
-}
-
-static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg)
-{
-	int i, val=0;
-	unsigned long flags;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	VALIDATE_CARD(card);
-        if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
-		strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
-		info.modify_counter = card->mix.modcnt;
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
-		strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
-		if (copy_to_user(argp, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, p);
-
-	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
-
-        if (_IOC_DIR(cmd) == _IOC_READ) {
-                switch (_IOC_NR(cmd)) {
-                case SOUND_MIXER_RECSRC: /* give them the current record source */
-
-			if(!card->mix.recmask_io) {
-				val = 0;
-			} else {
-                               spin_lock_irqsave(&card->lock, flags);
-				val = card->mix.recmask_io(card,1,0);
-                               spin_unlock_irqrestore(&card->lock, flags);
-			}
-			break;
-			
-                case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
-			val = card->mix.supported_mixers;
-			break;
-
-                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			val = card->mix.record_sources;
-			break;
-			
-                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			val = card->mix.stereo_mixers;
-			break;
-			
-                case SOUND_MIXER_CAPS:
-			val = SOUND_CAP_EXCL_INPUT;
-			break;
-
-		default: /* read a specific mixer */
-			i = _IOC_NR(cmd);
-
-			if ( ! supported_mixer(card,i)) 
-				return -EINVAL;
-
-			/* do we ever want to touch the hardware? */
-/*                     spin_lock_irqsave(&card->lock, flags);
-			val = card->mix.read_mixer(card,i);
-                       spin_unlock_irqrestore(&card->lock, flags);*/
-
-			val = card->mix.mixer_state[i];
-/*			M_printk("returned 0x%x for mixer %d\n",val,i);*/
-
-			break;
-		}
-		return put_user(val, p);
-	}
-	
-        if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
-		return -EINVAL;
-	
-	card->mix.modcnt++;
-
-	if (get_user(val, p))
-		return -EFAULT;
-
-	switch (_IOC_NR(cmd)) {
-	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-
-		if (!card->mix.recmask_io) return -EINVAL;
-		if(!val) return 0;
-		if(! (val &= card->mix.record_sources)) return -EINVAL;
-
-               spin_lock_irqsave(&card->lock, flags);
-		card->mix.recmask_io(card,0,val);
-               spin_unlock_irqrestore(&card->lock, flags);
-		return 0;
-
-	default:
-		i = _IOC_NR(cmd);
-
-		if ( ! supported_mixer(card,i)) 
-			return -EINVAL;
-
-               spin_lock_irqsave(&card->lock, flags);
-		set_mixer(card,i,val);
-               spin_unlock_irqrestore(&card->lock, flags);
-
-		return 0;
-	}
-}
-
-/* --------------------------------------------------------------------- */
-static int ess_open_mixdev(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct ess_card *card = NULL;
-	struct pci_dev *pdev = NULL;
-	struct pci_driver *drvr;
-
-	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-		drvr = pci_dev_driver (pdev);
-		if (drvr == &maestro_pci_driver) {
-			card = (struct ess_card*)pci_get_drvdata (pdev);
-			if (!card)
-				continue;
-			if (card->dev_mixer == minor)
-				break;
-		}
-	}
-	if (!card)
-		return -ENODEV;
-	file->private_data = card;
-	return nonseekable_open(inode, file);
-}
-
-static int ess_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct ess_card *card = (struct ess_card *)file->private_data;
-
-	VALIDATE_CARD(card);
-	
-	return 0;
-}
-
-static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct ess_card *card = (struct ess_card *)file->private_data;
-
-	VALIDATE_CARD(card);
-
-	return mixer_ioctl(card, cmd, arg);
-}
-
-static /*const*/ struct file_operations ess_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= ess_ioctl_mixdev,
-	.open		= ess_open_mixdev,
-	.release	= ess_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct ess_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait,current);
-	unsigned long flags;
-	int count;
-	signed long tmo;
-
-	if (s->dma_dac.mapped || !s->dma_dac.ready)
-		return 0;
-	current->state = TASK_INTERRUPTIBLE;
-        add_wait_queue(&s->dma_dac.wait, &wait);
-        for (;;) {
-		/* XXX uhm.. questionable locking*/
-                spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-                spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-                        break;
-                if (nonblock) {
-                        remove_wait_queue(&s->dma_dac.wait, &wait);
-			current->state = TASK_RUNNING;
-                        return -EBUSY;
-                }
-		tmo = (count * HZ) / s->ratedac;
-		tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
-		/* XXX this is just broken.  someone is waking us up alot, or schedule_timeout is broken.
-			or something.  who cares. - zach */
-		if (!schedule_timeout(tmo ? tmo : 1) && tmo)
-			M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies);
-        }
-        remove_wait_queue(&s->dma_dac.wait, &wait);
-	current->state = TASK_RUNNING;
-        if (signal_pending(current))
-                return -ERESTARTSYS;
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/* Zach sez: "god this is gross.." */
-static int 
-comb_stereo(unsigned char *real_buffer,unsigned char  *tmp_buffer, int offset, 
-	int count, int bufsize)
-{  
-	/* No such thing as stereo recording, so we
-	use dual input mixers.  which means we have to 
-	combine mono to stereo buffer.  yuck. 
-
-	but we don't have to be able to work a byte at a time..*/
-
-	unsigned char *so,*left,*right;
-	int i;
-
-	so = tmp_buffer;
-	left = real_buffer + offset;
-	right = real_buffer + bufsize/2 + offset;
-
-/*	M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/
-
-	for(i=count/4; i ; i--) {
-		(*(so+2)) = *(right++);
-		(*(so+3)) = *(right++);
-		(*so) = *(left++);
-		(*(so+1)) = *(left++);
-		so+=4;
-	}
-
-	return 0;
-}
-
-/* in this loop, dma_adc.count signifies the amount of data thats waiting
-	to be copied to the user's buffer.  it is filled by the interrupt
-	handler and drained by this loop. */
-static ssize_t 
-ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct ess_state *s = (struct ess_state *)file->private_data;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-	unsigned char *combbuf = NULL;
-	
-	VALIDATE_STATE(s);
-	if (s->dma_adc.mapped)
-		return -ENXIO;
-	if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	if(!(combbuf = kmalloc(count,GFP_KERNEL)))
-		return -ENOMEM;
-	ret = 0;
-
-	calc_bob_rate(s);
-
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		/* remember, all these things are expressed in bytes to be
-			sent to the user.. hence the evil / 2 down below */
-		swptr = s->dma_adc.swptr;
-		cnt = s->dma_adc.dmasize-swptr;
-		if (s->dma_adc.count < cnt)
-			cnt = s->dma_adc.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		if (cnt > count)
-			cnt = count;
-
-		if ( cnt > 0 ) cnt &= ~3;
-
-		if (cnt <= 0) {
-			start_adc(s);
-			if (file->f_flags & O_NONBLOCK) 
-			{
-				ret = ret ? ret : -EAGAIN;
-				goto rec_return_free;
-			}
-			if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
-				if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, 
-				       s->dma_adc.hwptr, s->dma_adc.swptr);
-				stop_adc(s);
-				spin_lock_irqsave(&s->lock, flags);
-				set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
-				/* program enhanced mode registers */
-				/* FILL ME */
-/*				wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
-				wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */
-				s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (signal_pending(current)) 
-			{
-				ret = ret ? ret : -ERESTARTSYS;
-				goto rec_return_free;
-			}
-			continue;
-		}
-	
-		if(s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
-			/* swptr/2 so that we know the real offset in each apu's buffer */
-			comb_stereo(s->dma_adc.rawbuf,combbuf,swptr/2,cnt,s->dma_adc.dmasize);
-			if (copy_to_user(buffer, combbuf, cnt)) {
-				ret = ret ? ret : -EFAULT;
-				goto rec_return_free;
-			}
-		} else  {
-			if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
-				ret = ret ? ret : -EFAULT;
-				goto rec_return_free;
-			}
-		}
-
-		swptr = (swptr + cnt) % s->dma_adc.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_adc.swptr = swptr;
-		s->dma_adc.count -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		start_adc(s);
-	}
-
-rec_return_free:
-	kfree(combbuf);
-	return ret;
-}
-
-static ssize_t 
-ess_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct ess_state *s = (struct ess_state *)file->private_data;
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-	
-	VALIDATE_STATE(s);
-	if (s->dma_dac.mapped)
-		return -ENXIO;
-	if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	ret = 0;
-
-	calc_bob_rate(s);
-
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-
-		if (s->dma_dac.count < 0) {
-			s->dma_dac.count = 0;
-			s->dma_dac.swptr = s->dma_dac.hwptr;
-		}
-		swptr = s->dma_dac.swptr;
-
-		cnt = s->dma_dac.dmasize-swptr;
-
-		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-			cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
-		spin_unlock_irqrestore(&s->lock, flags);
-
-		if (cnt > count)
-			cnt = count;
-
-		if (cnt <= 0) {
-			start_dac(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if(!ret) ret = -EAGAIN;
-				goto return_free;
-			}
-			if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
-				if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, 
-				       s->dma_dac.hwptr, s->dma_dac.swptr);
-				stop_dac(s);
-				spin_lock_irqsave(&s->lock, flags);
-				set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
-				/* program enhanced mode registers */
-/*				wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
-				wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */
-				/* FILL ME */
-				s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (signal_pending(current)) {
-				if (!ret) ret = -ERESTARTSYS;
-				goto return_free;
-			}
-			continue;
-		}
-		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-			if (!ret) ret = -EFAULT;
-			goto return_free;
-		}
-/*		printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/
-
-		swptr = (swptr + cnt) % s->dma_dac.dmasize;
-
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_dac.swptr = swptr;
-		s->dma_dac.count += cnt;
-		s->dma_dac.endcleared = 0;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		start_dac(s);
-	}
-return_free:
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct ess_state *s = (struct ess_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-
-/* In 0.14 prog_dmabuf always returns success anyway ... */
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready && prog_dmabuf(s, 0)) 
-			return 0;
-	}
-	if (file->f_mode & FMODE_READ) {
-	  	if (!s->dma_adc.ready && prog_dmabuf(s, 1))
-			return 0;
-	}
-
-	if (file->f_mode & FMODE_WRITE)
-		poll_wait(file, &s->dma_dac.wait, wait);
-	if (file->f_mode & FMODE_READ)
-		poll_wait(file, &s->dma_adc.wait, wait);
-	spin_lock_irqsave(&s->lock, flags);
-	ess_update_ptr(s);
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int ess_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct ess_state *s = (struct ess_state *)file->private_data;
-	struct dmabuf *db;
-	int ret = -EINVAL;
-	unsigned long size;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf(s, 1)) != 0)
-			goto out;
-		db = &s->dma_dac;
-	} else 
-#if 0
-	/* if we can have the wp/wc do the combining
-		we can turn this back on.  */
-	      if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf(s, 0)) != 0)
-			goto out;
-		db = &s->dma_adc;
-	} else  
-#endif
-		goto out;
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder))
-		goto out;
-	ret = -EAGAIN;
-	if (remap_pfn_range(vma, vma->vm_start,
-			virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
-			size, vma->vm_page_prot))
-		goto out;
-	db->mapped = 1;
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct ess_state *s = (struct ess_state *)file->private_data;
-	unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
-	int val, mapped, ret;
-	unsigned char fmtm, fmtd;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-/*	printk("maestro: ess_ioctl: cmd %d\n", cmd);*/
-	
-	VALIDATE_STATE(s);
-        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, file->f_flags & O_NONBLOCK);
-		return 0;
-		
-	case SNDCTL_DSP_SETDUPLEX:
-		/* XXX fix */
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-		
-        case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq(s->card->pcidev->irq);
-			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq(s->card->pcidev->irq);
-			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SPEED:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				set_adc_rate(s, val);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				set_dac_rate(s, val);
-			}
-		}
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-		
-        case SNDCTL_DSP_STEREO:
-		if (get_user(val, p))
-			return -EFAULT;
-		fmtd = 0;
-		fmtm = ~0;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ready = 0;
-			if (val)
-				fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
-			else
-				fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ready = 0;
-			if (val)
-				fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
-			else
-				fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
-		}
-		set_fmt(s, fmtm, fmtd);
-		return 0;
-
-        case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 0) {
-			fmtd = 0;
-			fmtm = ~0;
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val >= 2)
-					fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
-				else
-					fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val >= 2)
-					fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
-				else
-					fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
-			}
-			set_fmt(s, fmtm, fmtd);
-		}
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
-					   : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-		
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_U8|AFMT_S16_LE, p);
-		
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			fmtd = 0;
-			fmtm = ~0;
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-	/* fixed at 16bit for now */
-				fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
-#if 0
-				if (val == AFMT_S16_LE)
-					fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
-				else
-					fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
-#endif
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val == AFMT_S16_LE)
-					fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-				else
-					fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
-			}
-			set_fmt(s, fmtm, fmtd);
-		}
- 		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-			(ESS_FMT_16BIT << ESS_ADC_SHIFT) 
-			: (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 
-				AFMT_S16_LE : 
-				AFMT_U8, 
-			p);
-		
-	case SNDCTL_DSP_POST:
-                return 0;
-
-        case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
-			val |= PCM_ENABLE_INPUT;
-		if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) 
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, p);
-		
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-					return ret;
-				start_adc(s);
-			} else
-				stop_adc(s);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-					return ret;
-				start_dac(s);
-			} else
-				stop_dac(s);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
-		spin_lock_irqsave(&s->lock, flags);
-		ess_update_ptr(s);
-		abinfo.fragsize = s->dma_dac.fragsize;
-                abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
-                abinfo.fragstotal = s->dma_dac.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-			return ret;
-		spin_lock_irqsave(&s->lock, flags);
-		ess_update_ptr(s);
-		abinfo.fragsize = s->dma_adc.fragsize;
-                abinfo.bytes = s->dma_adc.count;
-                abinfo.fragstotal = s->dma_adc.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-		
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
-		spin_lock_irqsave(&s->lock, flags);
-		ess_update_ptr(s);
-                val = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		return put_user(val, p);
-
-        case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-			return ret;
-		spin_lock_irqsave(&s->lock, flags);
-		ess_update_ptr(s);
-                cinfo.bytes = s->dma_adc.total_bytes;
-                cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
-                cinfo.ptr = s->dma_adc.hwptr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= s->dma_adc.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-			return ret;
-		spin_lock_irqsave(&s->lock, flags);
-		ess_update_ptr(s);
-                cinfo.bytes = s->dma_dac.total_bytes;
-                cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
-                cinfo.ptr = s->dma_dac.hwptr;
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= s->dma_dac.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf(s, 0)))
-				return val;
-			return put_user(s->dma_dac.fragsize, p);
-		}
-		if ((val = prog_dmabuf(s, 1)))
-			return val;
-		return put_user(s->dma_adc.fragsize, p);
-
-        case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, p))
-			return -EFAULT;
-		M_printk("maestro: SETFRAGMENT: %0x\n",val);
-		if (file->f_mode & FMODE_READ) {
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-			return -EINVAL;
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			s->dma_dac.subdivision = val;
-		return 0;
-
-        case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
-					   : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
-        case SOUND_PCM_READ_BITS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
-					   : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
-
-        case SOUND_PCM_WRITE_FILTER:
-        case SNDCTL_DSP_SETSYNCRO:
-        case SOUND_PCM_READ_FILTER:
-                return -EINVAL;
-		
-	}
-	return -EINVAL;
-}
-
-static void
-set_base_registers(struct ess_state *s,void *vaddr)
-{
-	unsigned long packed_phys = virt_to_bus(vaddr)>>12;
-	wave_set_register(s, 0x01FC , packed_phys);
-	wave_set_register(s, 0x01FD , packed_phys);
-	wave_set_register(s, 0x01FE , packed_phys);
-	wave_set_register(s, 0x01FF , packed_phys);
-}
-
-/* 
- * this guy makes sure we're in the right power
- * state for what we want to be doing 
- */
-static void maestro_power(struct ess_card *card, int tostate)
-{
-	u16 active_mask = acpi_state_mask[tostate];
-	u8 state;
-
-	if(!use_pm) return;
-
-	pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state);
-	state&=3;
-
-	/* make sure we're in the right state */
-	if(state != tostate) {
-		M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n",
-			card->pcidev->bus->number, 
-			PCI_SLOT(card->pcidev->devfn),
-			PCI_FUNC(card->pcidev->devfn),
-			state,tostate);
-		pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate);
-	}
-
-	/* and make sure the units we care about are on 
-		XXX we might want to do this before state flipping? */
-	pci_write_config_word(card->pcidev, 0x54, ~ active_mask);
-	pci_write_config_word(card->pcidev, 0x56, ~ active_mask);
-}
-
-/* we allocate a large power of two for all our memory.
-	this is cut up into (not to scale :):
-	|silly fifo word	| 512byte mixbuf per adc	| dac/adc * channels |
-*/
-static int
-allocate_buffers(struct ess_state *s)
-{
-	void *rawbuf=NULL;
-	int order,i;
-	struct page *page, *pend;
-
-	/* alloc as big a chunk as we can */
-	for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
-		if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
-			break;
-
-	if (!rawbuf)
-		return 1;
-
-	M_printk("maestro: allocated %ld (%d) bytes at %p\n",PAGE_SIZE<<order,order, rawbuf);
-
-	if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~((1<<28)-1))  {
-		printk(KERN_ERR "maestro: DMA buffer beyond 256MB! busaddr 0x%lx  size %ld\n",
-			virt_to_bus(rawbuf), PAGE_SIZE << order);
-		kfree(rawbuf);
-		return 1;
-	}
-
-	s->card->dmapages = rawbuf;
-	s->card->dmaorder = order;
-
-	for(i=0;i<NR_DSPS;i++) {
-		struct ess_state *ess = &s->card->channels[i];
-
-		if(ess->dev_audio == -1)
-			continue;
-
-		ess->dma_dac.ready = s->dma_dac.mapped = 0;
-		ess->dma_adc.ready = s->dma_adc.mapped = 0;
-		ess->dma_adc.buforder = ess->dma_dac.buforder = order - 1 - dsps_order - 1;
-
-		/* offset dac and adc buffers starting half way through and then at each [da][ad]c's
-			order's intervals.. */
-		ess->dma_dac.rawbuf = rawbuf + (PAGE_SIZE<<(order-1)) + (i * ( PAGE_SIZE << (ess->dma_dac.buforder + 1 )));
-		ess->dma_adc.rawbuf = ess->dma_dac.rawbuf + ( PAGE_SIZE << ess->dma_dac.buforder);
-		/* offset mixbuf by a mixbuf so that the lame status fifo can
-			happily scribble away.. */ 
-		ess->mixbuf = rawbuf + (512 * (i+1));
-
-		M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf,
-			ess->dma_adc.rawbuf, ess->mixbuf);
-
-	}
-
-	/* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-	pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
-	for (page = virt_to_page(rawbuf); page <= pend; page++)
-		SetPageReserved(page);
-
-	return 0;
-} 
-static void
-free_buffers(struct ess_state *s)
-{
-	struct page *page, *pend;
-
-	s->dma_dac.rawbuf = s->dma_adc.rawbuf = NULL;
-	s->dma_dac.mapped = s->dma_adc.mapped = 0;
-	s->dma_dac.ready = s->dma_adc.ready = 0;
-
-	M_printk("maestro: freeing %p\n",s->card->dmapages);
-	/* undo marking the pages as reserved */
-
-	pend = virt_to_page(s->card->dmapages + (PAGE_SIZE << s->card->dmaorder) - 1);
-	for (page = virt_to_page(s->card->dmapages); page <= pend; page++)
-		ClearPageReserved(page);
-
-	free_pages((unsigned long)s->card->dmapages,s->card->dmaorder);
-	s->card->dmapages = NULL;
-}
-
-static int 
-ess_open(struct inode *inode, struct file *file)
-{
-	unsigned int minor = iminor(inode);
-	struct ess_state *s = NULL;
-	unsigned char fmtm = ~0, fmts = 0;
-	struct pci_dev *pdev = NULL;
-	/*
-	 *	Scan the cards and find the channel. We only
-	 *	do this at open time so it is ok
-	 */
-
-	while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
-		struct ess_card *c;
-		struct pci_driver *drvr;
-
-		drvr = pci_dev_driver (pdev);
-		if (drvr == &maestro_pci_driver) {
-			int i;
-			struct ess_state *sp;
-
-			c = (struct ess_card*)pci_get_drvdata (pdev);
-			if (!c)
-				continue;
-			for(i=0;i<NR_DSPS;i++)
-			{
-				sp=&c->channels[i];
-				if(sp->dev_audio < 0)
-					continue;
-				if((sp->dev_audio ^ minor) & ~0xf)
-					continue;
-				s=sp;
-			}
-		}
-	}
-	if (!s)
-		return -ENODEV;
-
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & file->f_mode) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EWOULDBLOCK;
-		}
-		mutex_unlock(&s->open_mutex);
-		interruptible_sleep_on(&s->open_wait);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-
-	/* under semaphore.. */
-	if ((s->card->dmapages==NULL) && allocate_buffers(s)) {
-		mutex_unlock(&s->open_mutex);
-		return -ENOMEM;
-	}
-
-	/* we're covered by the open_mutex */
-	if( ! s->card->dsps_open )  {
-		maestro_power(s->card,ACPI_D0);
-		start_bob(s);
-	}
-	s->card->dsps_open++;
-	M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
-
-	/* ok, lets write WC base regs now that we've 
-		powered up the chip */
-	M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages),
-		((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12);
-	set_base_registers(s,s->card->dmapages);
-
-	if (file->f_mode & FMODE_READ) {
-/*
-		fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; */
-
-		fmtm &= ~((ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT);
-		fmts = (ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT;
-
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
-		set_adc_rate(s, 8000);
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-
-		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
-		set_dac_rate(s, 8000);
-	}
-	set_fmt(s, fmtm, fmts);
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int 
-ess_release(struct inode *inode, struct file *file)
-{
-	struct ess_state *s = (struct ess_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE)
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac(s);
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-	}
-		
-	s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-	/* we're covered by the open_mutex */
-	M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
-	if( --s->card->dsps_open <= 0) {
-		s->card->dsps_open = 0;
-		stop_bob(s);
-		free_buffers(s);
-		maestro_power(s->card,ACPI_D2);
-	}
-	mutex_unlock(&s->open_mutex);
-	wake_up(&s->open_wait);
-	unlock_kernel();
-	return 0;
-}
-
-static struct file_operations ess_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= ess_read,
-	.write		= ess_write,
-	.poll		= ess_poll,
-	.ioctl		= ess_ioctl,
-	.mmap		= ess_mmap,
-	.open		= ess_open,
-	.release	= ess_release,
-};
-
-static int
-maestro_config(struct ess_card *card) 
-{
-	struct pci_dev *pcidev = card->pcidev;
-	struct ess_state *ess = &card->channels[0];
-	int apu,iobase  = card->iobase;
-	u16 w;
-	u32 n;
-
-	/* We used to muck around with pci config space that
-	 * we had no business messing with.  We don't know enough
-	 * about the machine to know which DMA mode is appropriate, 
-	 * etc.  We were guessing wrong on some machines and making
-	 * them unhappy.  We now trust in the BIOS to do things right,
-	 * which almost certainly means a new host of problems will
-	 * arise with broken BIOS implementations.  screw 'em. 
-	 * We're already intolerant of machines that don't assign
-	 * IRQs.
-	 */
-	
-	/* do config work at full power */
-	maestro_power(card,ACPI_D0);
-	 
-	pci_read_config_word(pcidev, 0x50, &w);
-
-	w&=~(1<<5);			/* Don't swap left/right (undoc)*/
-	
-	pci_write_config_word(pcidev, 0x50, w);
-	
-	pci_read_config_word(pcidev, 0x52, &w);
-	w&=~(1<<15);		/* Turn off internal clock multiplier */
-	/* XXX how do we know which to use? */
-	w&=~(1<<14);		/* External clock */
-	
-	w|= (1<<7);		/* Hardware volume control on */
-	w|= (1<<6);		/* Debounce off: easier to push the HWV buttons. */
-	w&=~(1<<5);		/* GPIO 4:5 */
-	w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
-	w&=~(1<<2);		/* MIDI fix off (undoc) */
-	w&=~(1<<1);		/* reserved, always write 0 */
-	pci_write_config_word(pcidev, 0x52, w);
-	
-	/*
-	 *	Legacy mode
-	 */
-
-	pci_read_config_word(pcidev, 0x40, &w);
-	w|=(1<<15);	/* legacy decode off */
-	w&=~(1<<14);	/* Disable SIRQ */
-	w&=~(0x1f);	/* disable mpu irq/io, game port, fm, SB */
-	 
-	pci_write_config_word(pcidev, 0x40, w);
-
-	/* Set up 978 docking control chip. */
-	pci_read_config_word(pcidev, 0x58, &w);
-	w|=1<<2;	/* Enable 978. */
-	w|=1<<3;	/* Turn on 978 hardware volume control. */
-	w&=~(1<<11);	/* Turn on 978 mixer volume control. */
-	pci_write_config_word(pcidev, 0x58, w);
-	
-	sound_reset(iobase);
-
-	/*
-	 *	Ring Bus Setup
-	 */
-
-	/* setup usual 0x34 stuff.. 0x36 may be chip specific */
-        outw(0xC090, iobase+0x34); /* direct sound, stereo */
-        udelay(20);
-        outw(0x3000, iobase+0x36); /* direct sound, stereo */
-        udelay(20);
-
-
-	/*
-	 *	Reset the CODEC
-	 */
-	 
-	maestro_ac97_reset(iobase,pcidev);
-	
-	/*
-	 *	Ring Bus Setup
-	 */
-	 	 
-	n=inl(iobase+0x34);
-	n&=~0xF000;
-	n|=12<<12;		/* Direct Sound, Stereo */
-	outl(n, iobase+0x34);
-
-	n=inl(iobase+0x34);
-	n&=~0x0F00;		/* Modem off */
-	outl(n, iobase+0x34);
-
-	n=inl(iobase+0x34);
-	n&=~0x00F0;
-	n|=9<<4;		/* DAC, Stereo */
-	outl(n, iobase+0x34);
-	
-	n=inl(iobase+0x34);
-	n&=~0x000F;		/* ASSP off */
-	outl(n, iobase+0x34);
-	
-	n=inl(iobase+0x34);
-	n|=(1<<29);		/* Enable ring bus */
-	outl(n, iobase+0x34);
-	
-	n=inl(iobase+0x34);
-	n|=(1<<28);		/* Enable serial bus */
-	outl(n, iobase+0x34);
-	
-	n=inl(iobase+0x34);
-	n&=~0x00F00000;		/* MIC off */
-	outl(n, iobase+0x34);
-	
-	n=inl(iobase+0x34);
-	n&=~0x000F0000;		/* I2S off */
-	outl(n, iobase+0x34);
-	
-
-	w=inw(iobase+0x18);
-	w&=~(1<<7);		/* ClkRun off */
-	outw(w, iobase+0x18);
-
-	w=inw(iobase+0x18);
-	w&=~(1<<6);		/* Hardware volume control interrupt off... for now. */
-	outw(w, iobase+0x18);
-	
-	w=inw(iobase+0x18);
-	w&=~(1<<4);		/* ASSP irq off */
-	outw(w, iobase+0x18);
-	
-	w=inw(iobase+0x18);
-	w&=~(1<<3);		/* ISDN irq off */
-	outw(w, iobase+0x18);
-	
-	w=inw(iobase+0x18);
-	w|=(1<<2);		/* Direct Sound IRQ on */
-	outw(w, iobase+0x18);
-
-	w=inw(iobase+0x18);
-	w&=~(1<<1);		/* MPU401 IRQ off */
-	outw(w, iobase+0x18);
-
-	w=inw(iobase+0x18);
-	w|=(1<<0);		/* SB IRQ on */
-	outw(w, iobase+0x18);
-
-	/* Set hardware volume control registers to midpoints.
-	   We can tell which button was pushed based on how they change. */
-	outb(0x88, iobase+0x1c);
-	outb(0x88, iobase+0x1d);
-	outb(0x88, iobase+0x1e);
-	outb(0x88, iobase+0x1f);
-
-	/* it appears some maestros (dell 7500) only work if these are set,
-		regardless of whether we use the assp or not. */
-
-	outb(0, iobase+0xA4); 
-	outb(3, iobase+0xA2); 
-	outb(0, iobase+0xA6);
-	
-	for(apu=0;apu<16;apu++)
-	{
-		/* Write 0 into the buffer area 0x1E0->1EF */
-		outw(0x01E0+apu, 0x10+iobase);
-		outw(0x0000, 0x12+iobase);
-	
-		/*
-		 * The 1.10 test program seem to write 0 into the buffer area
-		 * 0x1D0-0x1DF too.
-		 */
-		outw(0x01D0+apu, 0x10+iobase);
-		outw(0x0000, 0x12+iobase);
-	}
-
-#if 1
-	wave_set_register(ess, IDR7_WAVE_ROMRAM, 
-		(wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00));
-	wave_set_register(ess, IDR7_WAVE_ROMRAM,
-		wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100);
-	wave_set_register(ess, IDR7_WAVE_ROMRAM,
-		wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200);
-	wave_set_register(ess, IDR7_WAVE_ROMRAM,
-		wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400);
-#else		
-	maestro_write(ess, IDR7_WAVE_ROMRAM, 
-		(maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00));
-	maestro_write(ess, IDR7_WAVE_ROMRAM,
-		maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100);
-	maestro_write(ess, IDR7_WAVE_ROMRAM,
-		maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200);
-	maestro_write(ess, IDR7_WAVE_ROMRAM,
-		maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400);
-#endif
-	
-	maestro_write(ess, IDR2_CRAM_DATA, 0x0000);
-	maestro_write(ess, 0x08, 0xB004);
-	/* Now back to the DirectSound stuff */
-	maestro_write(ess, 0x09, 0x001B);
-	maestro_write(ess, 0x0A, 0x8000);
-	maestro_write(ess, 0x0B, 0x3F37);
-	maestro_write(ess, 0x0C, 0x0098);
-	
-	/* parallel out ?? */
-	maestro_write(ess, 0x0C, 
-		(maestro_read(ess, 0x0C)&~0xF000)|0x8000); 
-	/* parallel in, has something to do with recording :) */
-	maestro_write(ess, 0x0C, 
-		(maestro_read(ess, 0x0C)&~0x0F00)|0x0500);
-
-	maestro_write(ess, 0x0D, 0x7632);
-			
-	/* Wave cache control on - test off, sg off, 
-		enable, enable extra chans 1Mb */
-
-	outw(inw(0x14+iobase)|(1<<8),0x14+iobase);
-	outw(inw(0x14+iobase)&0xFE03,0x14+iobase);
-	outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase);
-	outw(inw(0x14+iobase)|(1<<7),0x14+iobase);
-
-	outw(0xA1A0, 0x14+iobase);      /* 0300 ? */
-
-	/* Now clear the APU control ram */	
-	for(apu=0;apu<NR_APUS;apu++)
-	{
-		for(w=0;w<NR_APU_REGS;w++)
-			apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0);
-		
-	}
-
-	return 0;
-	
-}
-
-/* this guy tries to find the pci power management
- * register bank.  this should really be in core
- * code somewhere.  1 on success. */
-static int
-parse_power(struct ess_card *card, struct pci_dev *pcidev)
-{
-	u32 n;
-	u16 w;
-	u8 next;
-	int max = 64;  /* an a 8bit guy pointing to 32bit guys
-				can only express so much. */
-
-	card->power_regs = 0;
-
-	/* check to see if we have a capabilities list in
-		the config register */
-	pci_read_config_word(pcidev, PCI_STATUS, &w);
-	if(!(w & PCI_STATUS_CAP_LIST)) return 0;
-
-	/* walk the list, starting at the head. */
-	pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next);
-
-	while(next && max--) {
-		pci_read_config_dword(pcidev, next & ~3, &n);
-		if((n & 0xff) == PCI_CAP_ID_PM) {
-			card->power_regs = next;
-			break;
-		}
-		next = ((n>>8) & 0xff);
-	}
-
-	return card->power_regs ? 1 : 0;
-}
-
-static int __init
-maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid)
-{
-	int card_type = pdid->driver_data;
-	u32 n;
-	int iobase;
-	int i, ret;
-	struct ess_card *card;
-	struct ess_state *ess;
-	int num = 0;
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
-	static int printed_version;
-	if (!printed_version++)
-		printk(version);
-#endif
-
-	/* don't pick up weird modem maestros */
-	if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
-		return -ENODEV;
-
-
-	if ((ret=pci_enable_device(pcidev)))
-		return ret;
-			
-	iobase = pci_resource_start(pcidev,0);
-	if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO))
-		return -ENODEV;
-
-	if(pcidev->irq == 0)
-		return -ENODEV;
-
-	/* stake our claim on the iospace */
-	if( request_region(iobase, 256, card_names[card_type]) == NULL )
-	{
-		printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
-		return -EBUSY;
-	}
-
-	/* just to be sure */
-	pci_set_master(pcidev);
-
-	card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
-	if(card == NULL)
-	{
-		printk(KERN_WARNING "maestro: out of memory\n");
-		release_region(iobase, 256);
-		return -ENOMEM;
-	}
-	
-	memset(card, 0, sizeof(*card));
-	card->pcidev = pcidev;
-
-	card->iobase = iobase;
-	card->card_type = card_type;
-	card->irq = pcidev->irq;
-	card->magic = ESS_CARD_MAGIC;
-	spin_lock_init(&card->lock);
-	init_waitqueue_head(&card->suspend_queue);
-
-	card->dock_mute_vol = 50;
-	
-	/* init our groups of 6 apus */
-	for(i=0;i<NR_DSPS;i++)
-	{
-		struct ess_state *s=&card->channels[i];
-
-		s->index = i;
-
-		s->card = card;
-		init_waitqueue_head(&s->dma_adc.wait);
-		init_waitqueue_head(&s->dma_dac.wait);
-		init_waitqueue_head(&s->open_wait);
-		spin_lock_init(&s->lock);
-		mutex_init(&s->open_mutex);
-		s->magic = ESS_STATE_MAGIC;
-		
-		s->apu[0] = 6*i;
-		s->apu[1] = (6*i)+1;
-		s->apu[2] = (6*i)+2;
-		s->apu[3] = (6*i)+3;
-		s->apu[4] = (6*i)+4;
-		s->apu[5] = (6*i)+5;
-		
-		if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
-			printk("maestro: BOTCH!\n");
-		/* register devices */
-		if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0)
-			break;
-	}
-	
-	num = i;
-	
-	/* clear the rest if we ran out of slots to register */
-	for(;i<NR_DSPS;i++)
-	{
-		struct ess_state *s=&card->channels[i];
-		s->dev_audio = -1;
-	}
-	
-	ess = &card->channels[0];
-
-	/*
-	 *	Ok card ready. Begin setup proper
-	 */
-
-	printk(KERN_INFO "maestro: Configuring %s found at IO 0x%04X IRQ %d\n", 
-		card_names[card_type],iobase,card->irq);
-	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
-	printk(KERN_INFO "maestro:  subvendor id: 0x%08x\n",n); 
-
-	/* turn off power management unless:
-	 *	- the user explicitly asks for it
-	 * 		or
-	 *		- we're not a 2e, lesser chipps seem to have problems.
-	 *		- we're not on our _very_ small whitelist.  some implemenetations
-	 *			really don't like the pm code, others require it.
-	 *			feel free to expand this as required.
-	 */
-#define SUBSYSTEM_VENDOR(x) (x&0xffff)
-	if(	(use_pm != 1) && 
-		((card_type != TYPE_MAESTRO2E)	|| (SUBSYSTEM_VENDOR(n) != 0x1028)))
-			use_pm = 0;
-
-	if(!use_pm) 
-		printk(KERN_INFO "maestro: not attempting power management.\n");
-	else {
-		if(!parse_power(card,pcidev)) 
-			printk(KERN_INFO "maestro: no PCI power management interface found.\n");
-		else {
-			pci_read_config_dword(pcidev, card->power_regs, &n);
-			printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16);
-		}	
-	}
-
-	maestro_config(card);
-
-	if(maestro_ac97_get(card, 0x00)==0x0080) {
-		printk(KERN_ERR "maestro: my goodness!  you seem to have a pt101 codec, which is quite rare.\n"
-				"\tyou should tell someone about this.\n");
-	} else {
-		maestro_ac97_init(card);
-	}
-
-	if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) {
-		printk("maestro: couldn't register mixer!\n");
-	} else {
-		memcpy(card->mix.mixer_state,mixer_defaults,sizeof(card->mix.mixer_state));
-		mixer_push_state(card);
-	}
-	
-	if((ret=request_irq(card->irq, ess_interrupt, IRQF_SHARED, card_names[card_type], card)))
-	{
-		printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq);
-		unregister_sound_mixer(card->dev_mixer);
-		for(i=0;i<NR_DSPS;i++)
-		{
-			struct ess_state *s = &card->channels[i];
-			if(s->dev_audio != -1)
-				unregister_sound_dsp(s->dev_audio);
-		}
-		release_region(card->iobase, 256);		
-		unregister_reboot_notifier(&maestro_nb);
-		kfree(card);
-		return ret;
-	}
-
-	/* Turn on hardware volume control interrupt.
-	   This has to come after we grab the IRQ above,
-	   or a crash will result on installation if a button has been pressed,
-	   because in that case we'll get an immediate interrupt. */
-	n = inw(iobase+0x18);
-	n|=(1<<6);
-	outw(n, iobase+0x18);
-
-	pci_set_drvdata(pcidev,card);
-	/* now go to sleep 'till something interesting happens */
-	maestro_power(card,ACPI_D2);
-
-	printk(KERN_INFO "maestro: %d channels configured.\n", num);
-	return 0;
-}
-
-static void maestro_remove(struct pci_dev *pcidev) {
-	struct ess_card *card = pci_get_drvdata(pcidev);
-	int i;
-	u32 n;
-	
-	/* XXX maybe should force stop bob, but should be all 
-		stopped by _release by now */
-
-	/* Turn off hardware volume control interrupt.
-	   This has to come before we leave the IRQ below,
-	   or a crash results if a button is pressed ! */
-	n = inw(card->iobase+0x18);
-	n&=~(1<<6);
-	outw(n, card->iobase+0x18);
-
-	free_irq(card->irq, card);
-	unregister_sound_mixer(card->dev_mixer);
-	for(i=0;i<NR_DSPS;i++)
-	{
-		struct ess_state *ess = &card->channels[i];
-		if(ess->dev_audio != -1)
-			unregister_sound_dsp(ess->dev_audio);
-	}
-	/* Goodbye, Mr. Bond. */
-	maestro_power(card,ACPI_D3);
- 	release_region(card->iobase, 256);
-	kfree(card);
-	pci_set_drvdata(pcidev,NULL);
-}
-
-static struct pci_device_id maestro_pci_tbl[] = {
-	{PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2},
-	{PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E},
-	{PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO},
-	{0,}
-};
-MODULE_DEVICE_TABLE(pci, maestro_pci_tbl);
-
-static struct pci_driver maestro_pci_driver = {
-	.name	  = "maestro",
-	.id_table = maestro_pci_tbl,
-	.probe	  = maestro_probe,
-	.remove	  = maestro_remove,
-};
-
-static int __init init_maestro(void)
-{
-	int rc;
-
-	rc = pci_register_driver(&maestro_pci_driver);
-	if (rc < 0)
-		return rc;
-
-	if (register_reboot_notifier(&maestro_nb))
-		printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
-#ifdef MODULE
-	printk(version);
-#endif
-	if (dsps_order < 0)   {
-		dsps_order = 1;
-		printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
-	}
-	else if (dsps_order > MAX_DSP_ORDER)  {
-		dsps_order = MAX_DSP_ORDER;
-		printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
-	}
-	return 0;
-}
-
-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
-{
-	/* this notifier is called when the kernel is really shut down. */
-	M_printk("maestro: shutting down\n");
-	/* this will remove all card instances too */
-	pci_unregister_driver(&maestro_pci_driver);
-	/* XXX dunno about power management */
-	return NOTIFY_OK;
-}
-
-/* --------------------------------------------------------------------- */
-
-
-static void cleanup_maestro(void) {
-	M_printk("maestro: unloading\n");
-	pci_unregister_driver(&maestro_pci_driver);
-	unregister_reboot_notifier(&maestro_nb);
-}
-
-/* --------------------------------------------------------------------- */
-
-void
-check_suspend(struct ess_card *card)
-{
-	DECLARE_WAITQUEUE(wait, current);
-
-	if(!card->in_suspend) return;
-
-	card->in_suspend++;
-	add_wait_queue(&(card->suspend_queue), &wait);
-	current->state = TASK_UNINTERRUPTIBLE;
-	schedule();
-	remove_wait_queue(&(card->suspend_queue), &wait);
-	current->state = TASK_RUNNING;
-}
-
-module_init(init_maestro);
-module_exit(cleanup_maestro);
diff --git a/sound/oss/maestro.h b/sound/oss/maestro.h
deleted file mode 100644
index 023ec7f..0000000
--- a/sound/oss/maestro.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *	Registers for the ESS PCI cards
- */
- 
-/*
- *	Memory access
- */
- 
-#define ESS_MEM_DATA		0x00
-#define	ESS_MEM_INDEX		0x02
-
-/*
- *	AC-97 Codec port. Delay 1uS after each write. This is used to
- *	talk AC-97 (see intel.com). Write data then register.
- */
- 
-#define ESS_AC97_INDEX		0x30		/* byte wide */
-#define ESS_AC97_DATA		0x32
-
-/* 
- *	Reading is a bit different. You write register|0x80 to ubdex
- *	delay 1uS poll the low bit of index, when it clears read the
- *	data value.
- */
-
-/*
- *	Control port. Not yet fully understood
- *	The value 0xC090 gets loaded to it then 0x0000 and 0x2800
- *	to the data port. Then after 4uS the value 0x300 is written
- */
- 
-#define RING_BUS_CTRL_L		0x34
-#define RING_BUS_CTRL_H		0x36
-
-/*
- *	This is also used during setup. The value 0x17 is written to it
- */
- 
-#define ESS_SETUP_18		0x18
-
-/*
- *	And this one gets 0x000b
- */
- 
-#define ESS_SETUP_A2		0xA2
-
-/*
- *	And this 0x0000
- */
- 
-#define ESS_SETUP_A4		0xA4
-#define ESS_SETUP_A6		0xA6
-
-/*
- *	Stuff to do with Harpo - the wave stuff
- */
- 
-#define ESS_WAVETABLE_SIZE	0x14
-#define 	ESS_WAVETABLE_2M	0xA180
-
diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c
deleted file mode 100644
index 5548e3c..0000000
--- a/sound/oss/maestro3.c
+++ /dev/null
@@ -1,2969 +0,0 @@
-/*****************************************************************************
- *
- *      ESS Maestro3/Allegro driver for Linux 2.4.x
- *
- *      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.
- *
- *    (c) Copyright 2000 Zach Brown <zab@zabbo.net>
- *
- * I need to thank many people for helping make this driver happen.  
- * As always, Eric Brombaugh was a hacking machine and killed many bugs
- * that I was too dumb to notice.  Howard Kim at ESS provided reference boards 
- * and as much docs as he could.  Todd and Mick at Dell tested snapshots on 
- * an army of laptops.  msw and deviant at Red Hat also humoured me by hanging
- * their laptops every few hours in the name of science.
- * 
- * Shouts go out to Mike "DJ XPCom" Ang.
- *
- * History
- *  v1.23 - Jun 5 2002 - Michael Olson <olson@cs.odu.edu>
- *   added a module option to allow selection of GPIO pin number 
- *   for external amp 
- *  v1.22 - Feb 28 2001 - Zach Brown <zab@zabbo.net>
- *   allocate mem at insmod/setup, rather than open
- *   limit pci dma addresses to 28bit, thanks guys.
- *  v1.21 - Feb 04 2001 - Zach Brown <zab@zabbo.net>
- *   fix up really dumb notifier -> suspend oops
- *  v1.20 - Jan 30 2001 - Zach Brown <zab@zabbo.net>
- *   get rid of pm callback and use pci_dev suspend/resume instead
- *   m3_probe cleanups, including pm oops think-o
- *  v1.10 - Jan 6 2001 - Zach Brown <zab@zabbo.net>
- *   revert to lame remap_page_range mmap() just to make it work
- *   record mmap fixed.
- *   fix up incredibly broken open/release resource management
- *   duh.  fix record format setting.
- *   add SMP locking and cleanup formatting here and there
- *  v1.00 - Dec 16 2000 - Zach Brown <zab@zabbo.net>
- *   port to sexy 2.4 interfaces
- *   properly align instance allocations so recording works
- *   clean up function namespace a little :/
- *   update PCI IDs based on mail from ESS
- *   arbitrarily bump version number to show its 2.4 now, 
- *      2.2 will stay 0., oss_audio port gets 2.
- *  v0.03 - Nov 05 2000 - Zach Brown <zab@zabbo.net>
- *   disable recording but allow dsp to be opened read 
- *   pull out most silly compat defines
- *  v0.02 - Nov 04 2000 - Zach Brown <zab@zabbo.net>
- *   changed clocking setup for m3, slowdown fixed.
- *   codec reset is hopefully reliable now
- *   rudimentary apm/power management makes suspend/resume work
- *  v0.01 - Oct 31 2000 - Zach Brown <zab@zabbo.net>
- *   first release
- *  v0.00 - Sep 09 2000 - Zach Brown <zab@zabbo.net>
- *   first pass derivation from maestro.c
- *
- * TODO
- *  in/out allocated contiguously so fullduplex mmap will work?
- *  no beep on init (mute)
- *  resetup msrc data memory if freq changes?
- *
- *  --
- *
- *  Allow me to ramble a bit about the m3 architecture.  The core of the
- *  chip is the 'assp', the custom ESS dsp that runs the show.  It has
- *  a small amount of code and data ram.  ESS drops binary dsp code images
- *  on our heads, but we don't get to see specs on the dsp.  
- *
- *  The constant piece of code on the dsp is the 'kernel'.  It also has a 
- *  chunk of the dsp memory that is statically set aside for its control
- *  info.  This is the KDATA defines in maestro3.h.  Part of its core
- *  data is a list of code addresses that point to the pieces of DSP code
- *  that it should walk through in its loop.  These other pieces of code
- *  do the real work.  The kernel presumably jumps into each of them in turn.
- *  These code images tend to have their own data area, and one can have
- *  multiple data areas representing different states for each of the 'client
- *  instance' code portions.  There is generally a list in the kernel data
- *  that points to the data instances for a given piece of code.
- *
- *  We've only been given the binary image for the 'minisrc', mini sample 
- *  rate converter.  This is rather annoying because it limits the work
- *  we can do on the dsp, but it also greatly simplifies the job of managing
- *  dsp data memory for the code and data for our playing streams :).  We
- *  statically allocate the minisrc code into a region we 'know' to be free
- *  based on the map of the binary kernel image we're loading.  We also 
- *  statically allocate the data areas for the maximum number of pcm streams
- *  we can be dealing with.  This max is set by the length of the static list
- *  in the kernel data that records the number of minisrc data regions we
- *  can have.  Thats right, all software dsp mixing with static code list
- *  limits.  Rock.
- *
- *  How sound goes in and out is still a relative mystery.  It appears
- *  that the dsp has the ability to get input and output through various
- *  'connections'.  To do IO from or to a connection, you put the address
- *  of the minisrc client area in the static kernel data lists for that 
- *  input or output.  so for pcm -> dsp -> mixer, we put the minisrc data
- *  instance in the DMA list and also in the list for the mixer.  I guess
- *  it Just Knows which is in/out, and we give some dma control info that
- *  helps.  There are all sorts of cool inputs/outputs that it seems we can't
- *  use without dsp code images that know how to use them.
- *
- *  So at init time we preload all the memory allocation stuff and set some
- *  system wide parameters.  When we really get a sound to play we build
- *  up its minisrc header (stream parameters, buffer addresses, input/output
- *  settings).  Then we throw its header on the various lists.  We also
- *  tickle some KDATA settings that ask the assp to raise clock interrupts
- *  and do some amount of software mixing before handing data to the ac97.
- *
- *  Sorry for the vague details.  Feel free to ask Eric or myself if you
- *  happen to be trying to use this driver elsewhere.  Please accept my
- *  apologies for the quality of the OSS support code, its passed through
- *  too many hands now and desperately wants to be rethought.
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/reboot.h>
-#include <linux/spinlock.h>
-#include <linux/ac97_codec.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "maestro3.h"
-
-#define M_DEBUG 1
-
-#define DRIVER_VERSION      "1.23"
-#define M3_MODULE_NAME      "maestro3"
-#define PFX                 M3_MODULE_NAME ": "
-
-#define M3_STATE_MAGIC      0x734d724d
-#define M3_CARD_MAGIC       0x646e6f50
-
-#define ESS_FMT_STEREO      0x01
-#define ESS_FMT_16BIT       0x02
-#define ESS_FMT_MASK        0x03
-#define ESS_DAC_SHIFT       0   
-#define ESS_ADC_SHIFT       4
-
-#define DAC_RUNNING         1
-#define ADC_RUNNING         2
-
-#define SND_DEV_DSP16       5 
-   
-#ifdef M_DEBUG
-static int debug;
-#define DPMOD   1   /* per module load */
-#define DPSTR   2   /* per 'stream' */
-#define DPSYS   3   /* per syscall */
-#define DPCRAP  4   /* stuff the user shouldn't see unless they're really debuggin */
-#define DPINT   5   /* per interrupt, LOTS */
-#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);}
-#else
-#define DPRINTK(x)
-#endif
-
-struct m3_list {
-    int curlen;
-    u16 mem_addr;
-    int max;
-};
-
-static int external_amp = 1;
-static int gpio_pin = -1;
-
-struct m3_state {
-    unsigned int magic;
-    struct m3_card *card;
-    unsigned char fmt, enable;
-
-    int index;
-
-    /* this locks around the oss state in the driver */
-	/* no, this lock is removed - only use card->lock */
-	/* otherwise: against what are you protecting on SMP 
-		when irqhandler uses s->lock
-		and m3_assp_read uses card->lock ?
-		*/
-    struct mutex open_mutex;
-    wait_queue_head_t open_wait;
-    mode_t open_mode;
-
-    int dev_audio;
-
-    struct assp_instance {
-        u16 code, data;
-    } dac_inst, adc_inst;
-
-    /* should be in dmabuf */
-    unsigned int rateadc, ratedac;
-
-    struct dmabuf {
-        void *rawbuf;
-        unsigned buforder;
-        unsigned numfrag;
-        unsigned fragshift;
-        unsigned hwptr, swptr;
-        unsigned total_bytes;
-        int count;
-        unsigned error; /* over/underrun */
-        wait_queue_head_t wait;
-        /* redundant, but makes calculations easier */
-        unsigned fragsize;
-        unsigned dmasize;
-        unsigned fragsamples;
-        /* OSS stuff */
-        unsigned mapped:1;
-        unsigned ready:1;    
-        unsigned endcleared:1;
-        unsigned ossfragshift;
-        int ossmaxfrags;
-        unsigned subdivision;
-        /* new in m3 */
-        int mixer_index, dma_index, msrc_index, adc1_index;
-        int in_lists;
-        /* 2.4.. */
-        dma_addr_t handle;
-
-    } dma_dac, dma_adc;
-};
-    
-struct m3_card {
-    unsigned int magic;
-
-    struct m3_card *next;
-
-    struct ac97_codec *ac97;
-    spinlock_t ac97_lock;
-
-    int card_type;
-
-#define NR_DSPS 1
-#define MAX_DSPS NR_DSPS
-    struct m3_state channels[MAX_DSPS];
-
-    /* this locks around the physical registers on the card */
-    spinlock_t lock;
-
-    /* hardware resources */
-    struct pci_dev *pcidev;
-    u32 iobase;
-    u32 irq;
-
-    int dacs_active;
-
-    int timer_users;
-
-    struct m3_list  msrc_list,
-                    mixer_list,
-                    adc1_list,
-                    dma_list;
-
-    /* for storing reset state..*/
-    u8 reset_state;
-
-    u16 *suspend_mem;
-    int in_suspend;
-    wait_queue_head_t suspend_queue;
-};
-
-/*
- * an arbitrary volume we set the internal
- * volume settings to so that the ac97 volume
- * range is a little less insane.  0x7fff is 
- * max.
- */
-#define ARB_VOLUME ( 0x6800 )
-
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-enum {
-    ESS_ALLEGRO,
-    ESS_MAESTRO3,
-    /*
-     * a maestro3 with 'hardware strapping', only
-     * found inside ESS?
-     */
-    ESS_MAESTRO3HW,
-};
-
-static char *card_names[] = {
-    [ESS_ALLEGRO] = "Allegro",
-    [ESS_MAESTRO3] = "Maestro3(i)",
-    [ESS_MAESTRO3HW] = "Maestro3(i)hw"
-};
-
-#ifndef PCI_VENDOR_ESS
-#define PCI_VENDOR_ESS      0x125D
-#endif
-
-#define M3_DEVICE(DEV, TYPE)			\
-{						\
-.vendor	     = PCI_VENDOR_ESS,			\
-.device	     = DEV,				\
-.subvendor   = PCI_ANY_ID,			\
-.subdevice   = PCI_ANY_ID,			\
-.class	     = PCI_CLASS_MULTIMEDIA_AUDIO << 8,	\
-.class_mask  = 0xffff << 8,			\
-.driver_data = TYPE,				\
-}
-
-static struct pci_device_id m3_id_table[] = {
-    M3_DEVICE(0x1988, ESS_ALLEGRO),
-    M3_DEVICE(0x1998, ESS_MAESTRO3),
-    M3_DEVICE(0x199a, ESS_MAESTRO3HW),
-    {0,}
-};
-
-MODULE_DEVICE_TABLE (pci, m3_id_table);
-
-/*
- * reports seem to indicate that the m3 is limited
- * to 28bit bus addresses.  aaaargggh...
- */
-#define M3_PCI_DMA_MASK 0x0fffffff
-
-static unsigned 
-ld2(unsigned int x)
-{
-    unsigned r = 0;
-    
-    if (x >= 0x10000) {
-        x >>= 16;
-        r += 16;
-    }
-    if (x >= 0x100) {
-        x >>= 8;
-        r += 8;
-    }
-    if (x >= 0x10) {
-        x >>= 4;
-        r += 4;
-    }
-    if (x >= 4) {
-        x >>= 2;
-        r += 2;
-    }
-    if (x >= 2)
-        r++;
-    return r;
-}
-
-static struct m3_card *devs;
-
-/*
- * I'm not very good at laying out functions in a file :)
- */
-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state);
-static void check_suspend(struct m3_card *card);
-
-static struct notifier_block m3_reboot_nb = {
-	.notifier_call = m3_notifier,
-};
-
-static void m3_outw(struct m3_card *card,
-        u16 value, unsigned long reg)
-{
-    check_suspend(card);
-    outw(value, card->iobase + reg);
-}
-
-static u16 m3_inw(struct m3_card *card, unsigned long reg)
-{
-    check_suspend(card);
-    return inw(card->iobase + reg);
-}
-static void m3_outb(struct m3_card *card, 
-        u8 value, unsigned long reg)
-{
-    check_suspend(card);
-    outb(value, card->iobase + reg);
-}
-static u8 m3_inb(struct m3_card *card, unsigned long reg)
-{
-    check_suspend(card);
-    return inb(card->iobase + reg);
-}
-
-/*
- * access 16bit words to the code or data regions of the dsp's memory.
- * index addresses 16bit words.
- */
-static u16 __m3_assp_read(struct m3_card *card, u16 region, u16 index)
-{
-    m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
-    m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
-    return m3_inw(card, DSP_PORT_MEMORY_DATA);
-}
-static u16 m3_assp_read(struct m3_card *card, u16 region, u16 index)
-{
-    unsigned long flags;
-    u16 ret;
-
-    spin_lock_irqsave(&(card->lock), flags);
-    ret = __m3_assp_read(card, region, index);
-    spin_unlock_irqrestore(&(card->lock), flags);
-
-    return ret;
-}
-
-static void __m3_assp_write(struct m3_card *card, 
-        u16 region, u16 index, u16 data)
-{
-    m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
-    m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
-    m3_outw(card, data, DSP_PORT_MEMORY_DATA);
-}
-static void m3_assp_write(struct m3_card *card, 
-        u16 region, u16 index, u16 data)
-{
-    unsigned long flags;
-
-    spin_lock_irqsave(&(card->lock), flags);
-    __m3_assp_write(card, region, index, data);
-    spin_unlock_irqrestore(&(card->lock), flags);
-}
-
-static void m3_assp_halt(struct m3_card *card)
-{
-    card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
-    mdelay(10);
-    m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
-}
-
-static void m3_assp_continue(struct m3_card *card)
-{
-    m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
-}
-
-/*
- * This makes me sad. the maestro3 has lists
- * internally that must be packed.. 0 terminates,
- * apparently, or maybe all unused entries have
- * to be 0, the lists have static lengths set
- * by the binary code images.
- */
-
-static int m3_add_list(struct m3_card *card,
-        struct m3_list *list, u16 val)
-{
-    DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n",
-            val, list, list->curlen);
-
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-            list->mem_addr + list->curlen,
-            val);
-
-    return list->curlen++;
-
-}
-
-static void m3_remove_list(struct m3_card *card,
-        struct m3_list *list, int index)
-{
-    u16  val;
-    int lastindex = list->curlen - 1;
-
-    DPRINTK(DPSTR, "removing ind %d from list 0x%p\n",
-            index, list);
-
-    if(index != lastindex) {
-        val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
-                list->mem_addr + lastindex);
-        m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-                list->mem_addr + index,
-                val);
-    }
-
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-            list->mem_addr + lastindex,
-            0);
-
-    list->curlen--;
-}
-
-static void set_fmt(struct m3_state *s, unsigned char mask, unsigned char data)
-{
-    int tmp;
-
-    s->fmt = (s->fmt & mask) | data;
-
-    tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
-
-    /* write to 'mono' word */
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1, 
-            (tmp & ESS_FMT_STEREO) ? 0 : 1);
-    /* write to '8bit' word */
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2, 
-            (tmp & ESS_FMT_16BIT) ? 0 : 1);
-
-    tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK;
-
-    /* write to 'mono' word */
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1, 
-            (tmp & ESS_FMT_STEREO) ? 0 : 1);
-    /* write to '8bit' word */
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2, 
-            (tmp & ESS_FMT_16BIT) ? 0 : 1);
-}
-
-static void set_dac_rate(struct m3_state *s, unsigned int rate)
-{
-    u32 freq;
-
-    if (rate > 48000)
-        rate = 48000;
-    if (rate < 8000)
-        rate = 8000;
-
-    s->ratedac = rate;
-
-    freq = ((rate << 15) + 24000 ) / 48000;
-    if(freq) 
-        freq--;
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->dac_inst.data + CDATA_FREQUENCY,
-            freq);
-}
-
-static void set_adc_rate(struct m3_state *s, unsigned int rate)
-{
-    u32 freq;
-
-    if (rate > 48000)
-        rate = 48000;
-    if (rate < 8000)
-        rate = 8000;
-
-    s->rateadc = rate;
-
-    freq = ((rate << 15) + 24000 ) / 48000;
-    if(freq) 
-        freq--;
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->adc_inst.data + CDATA_FREQUENCY,
-            freq);
-}
-
-static void inc_timer_users(struct m3_card *card)
-{
-    unsigned long flags;
-
-    spin_lock_irqsave(&card->lock, flags);
-    
-    card->timer_users++;
-    DPRINTK(DPSYS, "inc timer users now %d\n",
-            card->timer_users);
-    if(card->timer_users != 1) 
-        goto out;
-
-    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-        KDATA_TIMER_COUNT_RELOAD,
-         240 ) ;
-
-    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-        KDATA_TIMER_COUNT_CURRENT,
-         240 ) ;
-
-    m3_outw(card,  
-            m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE,
-            HOST_INT_CTRL);
-out:
-    spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void dec_timer_users(struct m3_card *card)
-{
-    unsigned long flags;
-
-    spin_lock_irqsave(&card->lock, flags);
-
-    card->timer_users--;
-    DPRINTK(DPSYS, "dec timer users now %d\n",
-            card->timer_users);
-    if(card->timer_users > 0 ) 
-        goto out;
-
-    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-        KDATA_TIMER_COUNT_RELOAD,
-         0 ) ;
-
-    __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-        KDATA_TIMER_COUNT_CURRENT,
-         0 ) ;
-
-    m3_outw(card,  m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE,
-            HOST_INT_CTRL);
-out:
-    spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/*
- * {start,stop}_{adc,dac} should be called
- * while holding the 'state' lock and they
- * will try to grab the 'card' lock..
- */
-static void stop_adc(struct m3_state *s)
-{
-    if (! (s->enable & ADC_RUNNING)) 
-        return;
-
-    s->enable &= ~ADC_RUNNING;
-    dec_timer_users(s->card);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->adc_inst.data + CDATA_INSTANCE_READY, 0);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            KDATA_ADC1_REQUEST, 0);
-}    
-
-static void stop_dac(struct m3_state *s)
-{
-    if (! (s->enable & DAC_RUNNING)) 
-        return;
-
-    DPRINTK(DPSYS, "stop_dac()\n");
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->dac_inst.data + CDATA_INSTANCE_READY, 0);
-
-    s->enable &= ~DAC_RUNNING;
-    s->card->dacs_active--;
-    dec_timer_users(s->card);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            KDATA_MIXER_TASK_NUMBER, 
-            s->card->dacs_active ) ;
-}    
-
-static void start_dac(struct m3_state *s)
-{
-    if( (!s->dma_dac.mapped && s->dma_dac.count < 1) ||
-            !s->dma_dac.ready ||
-            (s->enable & DAC_RUNNING)) 
-        return;
-
-    DPRINTK(DPSYS, "start_dac()\n");
-
-    s->enable |= DAC_RUNNING;
-    s->card->dacs_active++;
-    inc_timer_users(s->card);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->dac_inst.data + CDATA_INSTANCE_READY, 1);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            KDATA_MIXER_TASK_NUMBER, 
-            s->card->dacs_active ) ;
-}    
-
-static void start_adc(struct m3_state *s)
-{
-    if ((! s->dma_adc.mapped &&
-                s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
-        || !s->dma_adc.ready 
-        || (s->enable & ADC_RUNNING) ) 
-            return;
-
-    DPRINTK(DPSYS, "start_adc()\n");
-
-    s->enable |= ADC_RUNNING;
-    inc_timer_users(s->card);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            KDATA_ADC1_REQUEST, 1);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->adc_inst.data + CDATA_INSTANCE_READY, 1);
-}    
-
-static struct play_vals {
-    u16 addr, val;
-} pv[] = {
-    {CDATA_LEFT_VOLUME, ARB_VOLUME},
-    {CDATA_RIGHT_VOLUME, ARB_VOLUME},
-    {SRC3_DIRECTION_OFFSET, 0} ,
-    /* +1, +2 are stereo/16 bit */
-    {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
-    {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
-    {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
-    {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
-    {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
-    {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
-    {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
-    {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
-    {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
-    {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
-    {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
-    {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
-    {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */
-    {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */
-    {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */
-    {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
-    {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */
-};
-
-
-/* the mode passed should be already shifted and masked */
-static void m3_play_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
-{
-    int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
-    int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
-    int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
-    int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
-    struct dmabuf *db = &s->dma_dac;
-    int i;
-
-    DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n",
-        mode, rate, buffer, size);
-
-#define LO(x) ((x) & 0xffff)
-#define HI(x) LO((x) >> 16)
-
-    /* host dma buffer pointers */
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_HOST_SRC_ADDRL,
-        LO(virt_to_bus(buffer)));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_HOST_SRC_ADDRH,
-        HI(virt_to_bus(buffer)));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
-        LO(virt_to_bus(buffer) + size));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
-        HI(virt_to_bus(buffer) + size));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_HOST_SRC_CURRENTL,
-        LO(virt_to_bus(buffer)));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_HOST_SRC_CURRENTH,
-        HI(virt_to_bus(buffer)));
-#undef LO
-#undef HI
-
-    /* dsp buffers */
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_IN_BUF_BEGIN,
-        dsp_in_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1,
-        dsp_in_buffer + (dsp_in_size / 2));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_IN_BUF_HEAD,
-        dsp_in_buffer);
-    
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_IN_BUF_TAIL,
-        dsp_in_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_OUT_BUF_BEGIN,
-        dsp_out_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1,
-        dsp_out_buffer + (dsp_out_size / 2));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_OUT_BUF_HEAD,
-        dsp_out_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_OUT_BUF_TAIL,
-        dsp_out_buffer);
-
-    /*
-     * some per client initializers
-     */
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12,
-        s->dac_inst.data + 40 + 8);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19,
-        s->dac_inst.code + MINISRC_COEF_LOC);
-
-    /* enable or disable low pass filter? */
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22,
-        s->ratedac > 45000 ? 0xff : 0 );
-    
-    /* tell it which way dma is going? */
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->dac_inst.data + CDATA_DMA_CONTROL,
-        DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
-
-    /*
-     * set an armload of static initializers
-     */
-    for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++) 
-        m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->dac_inst.data + pv[i].addr, pv[i].val);
-
-    /* 
-     * put us in the lists if we're not already there
-     */
-
-    if(db->in_lists == 0) {
-
-        db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, 
-                s->dac_inst.data >> DP_SHIFT_COUNT);
-
-        db->dma_index = m3_add_list(s->card, &s->card->dma_list, 
-                s->dac_inst.data >> DP_SHIFT_COUNT);
-
-        db->mixer_index = m3_add_list(s->card, &s->card->mixer_list, 
-                s->dac_inst.data >> DP_SHIFT_COUNT);
-
-        db->in_lists = 1;
-    }
-
-    set_dac_rate(s,rate);
-    start_dac(s);
-}
-
-/*
- *    Native record driver 
- */
-static struct rec_vals {
-    u16 addr, val;
-} rv[] = {
-    {CDATA_LEFT_VOLUME, ARB_VOLUME},
-    {CDATA_RIGHT_VOLUME, ARB_VOLUME},
-    {SRC3_DIRECTION_OFFSET, 1} ,
-    /* +1, +2 are stereo/16 bit */
-    {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
-    {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
-    {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
-    {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
-    {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
-    {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
-    {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
-    {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
-    {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
-    {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
-    {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
-    {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
-    {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */
-    {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */
-    {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */
-    {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */
-    {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
-    {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */
-    {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */
-};
-
-/* again, passed mode is alrady shifted/masked */
-static void m3_rec_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
-{
-    int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
-    int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
-    int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
-    int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
-    struct dmabuf *db = &s->dma_adc;
-    int i;
-
-    DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n",
-        mode, rate, buffer, size);
-
-#define LO(x) ((x) & 0xffff)
-#define HI(x) LO((x) >> 16)
-
-    /* host dma buffer pointers */
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_HOST_SRC_ADDRL,
-        LO(virt_to_bus(buffer)));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_HOST_SRC_ADDRH,
-        HI(virt_to_bus(buffer)));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
-        LO(virt_to_bus(buffer) + size));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
-        HI(virt_to_bus(buffer) + size));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_HOST_SRC_CURRENTL,
-        LO(virt_to_bus(buffer)));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_HOST_SRC_CURRENTH,
-        HI(virt_to_bus(buffer)));
-#undef LO
-#undef HI
-
-    /* dsp buffers */
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_IN_BUF_BEGIN,
-        dsp_in_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1,
-        dsp_in_buffer + (dsp_in_size / 2));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_IN_BUF_HEAD,
-        dsp_in_buffer);
-    
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_IN_BUF_TAIL,
-        dsp_in_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_OUT_BUF_BEGIN,
-        dsp_out_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1,
-        dsp_out_buffer + (dsp_out_size / 2));
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_OUT_BUF_HEAD,
-        dsp_out_buffer);
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_OUT_BUF_TAIL,
-        dsp_out_buffer);
-
-    /*
-     * some per client initializers
-     */
-
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12,
-        s->adc_inst.data + 40 + 8);
-
-    /* tell it which way dma is going? */
-    m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-        s->adc_inst.data + CDATA_DMA_CONTROL,
-        DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT + 
-        DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
-
-    /*
-     * set an armload of static initializers
-     */
-    for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++) 
-        m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
-            s->adc_inst.data + rv[i].addr, rv[i].val);
-
-    /* 
-     * put us in the lists if we're not already there
-     */
-
-    if(db->in_lists == 0) {
-
-        db->adc1_index = m3_add_list(s->card, &s->card->adc1_list, 
-                s->adc_inst.data >> DP_SHIFT_COUNT);
-
-        db->dma_index = m3_add_list(s->card, &s->card->dma_list, 
-                s->adc_inst.data >> DP_SHIFT_COUNT);
-
-        db->msrc_index = m3_add_list(s->card, &s->card->msrc_list, 
-                s->adc_inst.data >> DP_SHIFT_COUNT);
-
-        db->in_lists = 1;
-    }
-
-    set_adc_rate(s,rate);
-    start_adc(s);
-}
-/* --------------------------------------------------------------------- */
-
-static void set_dmaa(struct m3_state *s, unsigned int addr, unsigned int count)
-{
-    DPRINTK(DPINT,"set_dmaa??\n");
-}
-
-static void set_dmac(struct m3_state *s, unsigned int addr, unsigned int count)
-{
-    DPRINTK(DPINT,"set_dmac??\n");
-}
-
-static u32 get_dma_pos(struct m3_card *card,
-		       int instance_addr)
-{
-    u16 hi = 0, lo = 0;
-    int retry = 10;
-
-    /*
-     * try and get a valid answer
-     */
-    while(retry--) {
-        hi =  m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
-                instance_addr + CDATA_HOST_SRC_CURRENTH);
-
-        lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
-                instance_addr + CDATA_HOST_SRC_CURRENTL);
-
-        if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
-                instance_addr + CDATA_HOST_SRC_CURRENTH))
-            break;
-    }
-    return lo | (hi<<16);
-}
-
-static u32 get_dmaa(struct m3_state *s)
-{
-    u32 offset;
-
-    offset = get_dma_pos(s->card, s->dac_inst.data) - 
-        virt_to_bus(s->dma_dac.rawbuf);
-
-    DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset);
-
-    return offset;
-}
-
-static u32 get_dmac(struct m3_state *s)
-{
-    u32 offset;
-
-    offset = get_dma_pos(s->card, s->adc_inst.data) -
-        virt_to_bus(s->dma_adc.rawbuf);
-
-    DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset);
-
-    return offset;
-
-}
-
-static int 
-prog_dmabuf(struct m3_state *s, unsigned rec)
-{
-    struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
-    unsigned rate = rec ? s->rateadc : s->ratedac;
-    unsigned bytepersec;
-    unsigned bufs;
-    unsigned char fmt;
-    unsigned long flags;
-
-    spin_lock_irqsave(&s->card->lock, flags);
-
-    fmt = s->fmt;
-    if (rec) {
-        stop_adc(s);
-        fmt >>= ESS_ADC_SHIFT;
-    } else {
-        stop_dac(s);
-        fmt >>= ESS_DAC_SHIFT;
-    }
-    fmt &= ESS_FMT_MASK;
-
-    db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
-    bytepersec = rate << sample_shift[fmt];
-    bufs = PAGE_SIZE << db->buforder;
-    if (db->ossfragshift) {
-        if ((1000 << db->ossfragshift) < bytepersec)
-            db->fragshift = ld2(bytepersec/1000);
-        else
-            db->fragshift = db->ossfragshift;
-    } else {
-        db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-        if (db->fragshift < 3)
-            db->fragshift = 3; 
-    }
-    db->numfrag = bufs >> db->fragshift;
-    while (db->numfrag < 4 && db->fragshift > 3) {
-        db->fragshift--;
-        db->numfrag = bufs >> db->fragshift;
-    }
-    db->fragsize = 1 << db->fragshift;
-    if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-        db->numfrag = db->ossmaxfrags;
-    db->fragsamples = db->fragsize >> sample_shift[fmt];
-    db->dmasize = db->numfrag << db->fragshift;
-
-    DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
-
-    memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
-
-    if (rec) 
-        m3_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
-    else 
-        m3_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
-
-    db->ready = 1;
-
-    spin_unlock_irqrestore(&s->card->lock, flags);
-
-    return 0;
-}
-
-static void clear_advance(struct m3_state *s)
-{
-    unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
-    
-    unsigned char *buf = s->dma_dac.rawbuf;
-    unsigned bsize = s->dma_dac.dmasize;
-    unsigned bptr = s->dma_dac.swptr;
-    unsigned len = s->dma_dac.fragsize;
-    
-    if (bptr + len > bsize) {
-        unsigned x = bsize - bptr;
-        memset(buf + bptr, c, x);
-        /* account for wrapping? */
-        bptr = 0;
-        len -= x;
-    }
-    memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void m3_update_ptr(struct m3_state *s)
-{
-    unsigned hwptr;
-    int diff;
-
-    /* update ADC pointer */
-    if (s->dma_adc.ready) {
-        hwptr = get_dmac(s) % s->dma_adc.dmasize;
-        diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
-        s->dma_adc.hwptr = hwptr;
-        s->dma_adc.total_bytes += diff;
-        s->dma_adc.count += diff;
-        if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
-            wake_up(&s->dma_adc.wait);
-        if (!s->dma_adc.mapped) {
-            if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-                stop_adc(s); 
-                /* brute force everyone back in sync, sigh */
-                s->dma_adc.count = 0;
-                s->dma_adc.swptr = 0;
-                s->dma_adc.hwptr = 0;
-                s->dma_adc.error++;
-            }
-        }
-    }
-    /* update DAC pointer */
-    if (s->dma_dac.ready) {
-        hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
-        diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-
-        DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n",
-                hwptr,diff,s->dma_dac.count);
-
-        s->dma_dac.hwptr = hwptr;
-        s->dma_dac.total_bytes += diff;
-
-        if (s->dma_dac.mapped) {
-            
-            s->dma_dac.count += diff;
-            if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
-                wake_up(&s->dma_dac.wait);
-            }
-        } else {
-
-            s->dma_dac.count -= diff;
-            
-            if (s->dma_dac.count <= 0) {
-                DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n", 
-                        diff, diff, 
-                        s->dma_dac.count, 
-                        s->dma_dac.count, 
-                    hwptr, hwptr,
-                    s->dma_dac.swptr,
-                    s->dma_dac.swptr);
-                stop_dac(s);
-                /* brute force everyone back in sync, sigh */
-                s->dma_dac.count = 0; 
-                s->dma_dac.swptr = hwptr; 
-                s->dma_dac.error++;
-            } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
-                clear_advance(s);
-                s->dma_dac.endcleared = 1;
-            }
-            if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
-                wake_up(&s->dma_dac.wait);
-                DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n",
-                        s->dma_dac.count, s->dma_dac.swptr, hwptr);
-            }
-        }
-    }
-}
-
-static irqreturn_t m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-    struct m3_card *c = (struct m3_card *)dev_id;
-    struct m3_state *s = &c->channels[0];
-    u8 status;
-
-    status = inb(c->iobase+0x1A);
-
-    if(status == 0xff)
-	return IRQ_NONE;
-   
-    /* presumably acking the ints? */
-    outw(status, c->iobase+0x1A); 
-
-    if(c->in_suspend)
-        return IRQ_HANDLED;
-
-    /*
-     * ack an assp int if its running
-     * and has an int pending
-     */
-    if( status & ASSP_INT_PENDING) {
-        u8 ctl = inb(c->iobase + ASSP_CONTROL_B);
-        if( !(ctl & STOP_ASSP_CLOCK)) {
-            ctl = inb(c->iobase + ASSP_HOST_INT_STATUS );
-            if(ctl & DSP2HOST_REQ_TIMER) {
-                outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS);
-                /* update adc/dac info if it was a timer int */
-                spin_lock(&c->lock);
-                m3_update_ptr(s);
-                spin_unlock(&c->lock);
-            }
-        }
-    }
-
-    /* XXX is this needed? */
-    if(status & 0x40) 
-        outb(0x40, c->iobase+0x1A);
-    return IRQ_HANDLED;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n";
-
-#define VALIDATE_MAGIC(FOO,MAG)                         \
-({                                                \
-    if (!(FOO) || (FOO)->magic != MAG) { \
-        printk(invalid_magic,__FUNCTION__);            \
-        return -ENXIO;                    \
-    }                                         \
-})
-
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC)
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct m3_state *s, int nonblock)
-{
-    DECLARE_WAITQUEUE(wait,current);
-    unsigned long flags;
-    int count;
-    signed long tmo;
-
-    if (s->dma_dac.mapped || !s->dma_dac.ready)
-        return 0;
-    set_current_state(TASK_INTERRUPTIBLE);
-    add_wait_queue(&s->dma_dac.wait, &wait);
-    for (;;) {
-        spin_lock_irqsave(&s->card->lock, flags);
-        count = s->dma_dac.count;
-        spin_unlock_irqrestore(&s->card->lock, flags);
-        if (count <= 0)
-            break;
-        if (signal_pending(current))
-            break;
-        if (nonblock) {
-            remove_wait_queue(&s->dma_dac.wait, &wait);
-            set_current_state(TASK_RUNNING);
-            return -EBUSY;
-        }
-        tmo = (count * HZ) / s->ratedac;
-        tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
-        /* XXX this is just broken.  someone is waking us up alot, or schedule_timeout is broken.
-            or something.  who cares. - zach */
-        if (!schedule_timeout(tmo ? tmo : 1) && tmo)
-            DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies);
-    }
-    remove_wait_queue(&s->dma_dac.wait, &wait);
-    set_current_state(TASK_RUNNING);
-    if (signal_pending(current))
-            return -ERESTARTSYS;
-    return 0;
-}
-
-static ssize_t m3_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-    struct m3_state *s = (struct m3_state *)file->private_data;
-    ssize_t ret;
-    unsigned long flags;
-    unsigned swptr;
-    int cnt;
-    
-    VALIDATE_STATE(s);
-    if (s->dma_adc.mapped)
-        return -ENXIO;
-    if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
-        return ret;
-    if (!access_ok(VERIFY_WRITE, buffer, count))
-        return -EFAULT;
-    ret = 0;
-
-    spin_lock_irqsave(&s->card->lock, flags);
-
-    while (count > 0) {
-        int timed_out;
-
-        swptr = s->dma_adc.swptr;
-        cnt = s->dma_adc.dmasize-swptr;
-        if (s->dma_adc.count < cnt)
-            cnt = s->dma_adc.count;
-
-        if (cnt > count)
-            cnt = count;
-
-        if (cnt <= 0) {
-            start_adc(s);
-            if (file->f_flags & O_NONBLOCK) 
-            {
-                ret = ret ? ret : -EAGAIN;
-                goto out;
-            }
-
-            spin_unlock_irqrestore(&s->card->lock, flags);
-            timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0;
-            spin_lock_irqsave(&s->card->lock, flags);
-
-            if(timed_out) {
-                printk("read: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
-                       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, 
-                       s->dma_adc.hwptr, s->dma_adc.swptr);
-                stop_adc(s);
-                set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
-                s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
-            }
-            if (signal_pending(current)) 
-            {
-                ret = ret ? ret : -ERESTARTSYS;
-                goto out;
-            }
-            continue;
-        }
-    
-        spin_unlock_irqrestore(&s->card->lock, flags);
-        if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
-            ret = ret ? ret : -EFAULT;
-            return ret;
-        }
-        spin_lock_irqsave(&s->card->lock, flags);
-
-        swptr = (swptr + cnt) % s->dma_adc.dmasize;
-        s->dma_adc.swptr = swptr;
-        s->dma_adc.count -= cnt;
-        count -= cnt;
-        buffer += cnt;
-        ret += cnt;
-        start_adc(s);
-    }
-
-out:
-    spin_unlock_irqrestore(&s->card->lock, flags);
-    return ret;
-}
-
-static ssize_t m3_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-    struct m3_state *s = (struct m3_state *)file->private_data;
-    ssize_t ret;
-    unsigned long flags;
-    unsigned swptr;
-    int cnt;
-    
-    VALIDATE_STATE(s);
-    if (s->dma_dac.mapped)
-        return -ENXIO;
-    if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-        return ret;
-    if (!access_ok(VERIFY_READ, buffer, count))
-        return -EFAULT;
-    ret = 0;
-
-    spin_lock_irqsave(&s->card->lock, flags);
-
-    while (count > 0) {
-        int timed_out;
-
-        if (s->dma_dac.count < 0) {
-            s->dma_dac.count = 0;
-            s->dma_dac.swptr = s->dma_dac.hwptr;
-        }
-        swptr = s->dma_dac.swptr;
-
-        cnt = s->dma_dac.dmasize-swptr;
-
-        if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-            cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
-
-        if (cnt > count)
-            cnt = count;
-
-        if (cnt <= 0) {
-            start_dac(s);
-            if (file->f_flags & O_NONBLOCK) {
-                if(!ret) ret = -EAGAIN;
-                goto out;
-            }
-            spin_unlock_irqrestore(&s->card->lock, flags);
-            timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0;
-            spin_lock_irqsave(&s->card->lock, flags);
-            if(timed_out) {
-                DPRINTK(DPCRAP,"write: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
-                       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, 
-                       s->dma_dac.hwptr, s->dma_dac.swptr);
-                stop_dac(s);
-                set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
-                s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
-            }
-            if (signal_pending(current)) {
-                if (!ret) ret = -ERESTARTSYS;
-                goto out;
-            }
-            continue;
-        }
-        spin_unlock_irqrestore(&s->card->lock, flags);
-        if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-            if (!ret) ret = -EFAULT;
-            return ret;
-        }
-        spin_lock_irqsave(&s->card->lock, flags);
-
-        DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n",
-                cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);
-        
-        swptr = (swptr + cnt) % s->dma_dac.dmasize;
-
-        s->dma_dac.swptr = swptr;
-        s->dma_dac.count += cnt;
-        s->dma_dac.endcleared = 0;
-        count -= cnt;
-        buffer += cnt;
-        ret += cnt;
-        start_dac(s);
-    }
-out:
-    spin_unlock_irqrestore(&s->card->lock, flags);
-    return ret;
-}
-
-static unsigned int m3_poll(struct file *file, struct poll_table_struct *wait)
-{
-    struct m3_state *s = (struct m3_state *)file->private_data;
-    unsigned long flags;
-    unsigned int mask = 0;
-
-    VALIDATE_STATE(s);
-    if (file->f_mode & FMODE_WRITE)
-        poll_wait(file, &s->dma_dac.wait, wait);
-    if (file->f_mode & FMODE_READ)
-        poll_wait(file, &s->dma_adc.wait, wait);
-
-    spin_lock_irqsave(&s->card->lock, flags);
-    m3_update_ptr(s);
-
-    if (file->f_mode & FMODE_READ) {
-        if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-            mask |= POLLIN | POLLRDNORM;
-    }
-    if (file->f_mode & FMODE_WRITE) {
-        if (s->dma_dac.mapped) {
-            if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
-                mask |= POLLOUT | POLLWRNORM;
-        } else {
-            if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
-                mask |= POLLOUT | POLLWRNORM;
-        }
-    }
-
-    spin_unlock_irqrestore(&s->card->lock, flags);
-    return mask;
-}
-
-static int m3_mmap(struct file *file, struct vm_area_struct *vma)
-{
-    struct m3_state *s = (struct m3_state *)file->private_data;
-    unsigned long max_size, size, start, offset;
-    struct dmabuf *db;
-    int ret = -EINVAL;
-
-    VALIDATE_STATE(s);
-    if (vma->vm_flags & VM_WRITE) {
-        if ((ret = prog_dmabuf(s, 0)) != 0)
-            return ret;
-        db = &s->dma_dac;
-    } else 
-    if (vma->vm_flags & VM_READ) {
-        if ((ret = prog_dmabuf(s, 1)) != 0)
-            return ret;
-        db = &s->dma_adc;
-    } else  
-        return -EINVAL;
-
-    max_size = db->dmasize;
-
-    start = vma->vm_start;
-    offset = (vma->vm_pgoff << PAGE_SHIFT);
-    size = vma->vm_end - vma->vm_start;
-
-    if(size > max_size)
-        goto out;
-    if(offset > max_size - size)
-        goto out;
-
-    /*
-     * this will be ->nopage() once I can 
-     * ask Jeff what the hell I'm doing wrong.
-     */
-    ret = -EAGAIN;
-    if (remap_pfn_range(vma, vma->vm_start,
-			virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
-			size, vma->vm_page_prot))
-        goto out;
-
-    db->mapped = 1;
-    ret = 0;
-
-out:
-    return ret;
-}
-
-/*
- * this function is a disaster..
- */
-#define get_user_ret(x, ptr,  ret) ({ if(get_user(x, ptr)) return ret; })
-static int m3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-    struct m3_state *s = (struct m3_state *)file->private_data;
-	struct m3_card *card=s->card;
-    unsigned long flags;
-    audio_buf_info abinfo;
-    count_info cinfo;
-    int val, mapped, ret;
-    unsigned char fmtm, fmtd;
-    void __user *argp = (void __user *)arg;
-    int __user *p = argp;
-
-    VALIDATE_STATE(s);
-
-    mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-        ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-    DPRINTK(DPSYS,"m3_ioctl: cmd %d\n", cmd);
-
-    switch (cmd) {
-    case OSS_GETVERSION:
-        return put_user(SOUND_VERSION, p);
-
-    case SNDCTL_DSP_SYNC:
-        if (file->f_mode & FMODE_WRITE)
-            return drain_dac(s, file->f_flags & O_NONBLOCK);
-        return 0;
-        
-    case SNDCTL_DSP_SETDUPLEX:
-        /* XXX fix */
-        return 0;
-
-    case SNDCTL_DSP_GETCAPS:
-        return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-        
-    case SNDCTL_DSP_RESET:
-        spin_lock_irqsave(&card->lock, flags);
-        if (file->f_mode & FMODE_WRITE) {
-            stop_dac(s);
-            synchronize_irq(s->card->pcidev->irq);
-            s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
-        }
-        if (file->f_mode & FMODE_READ) {
-            stop_adc(s);
-            synchronize_irq(s->card->pcidev->irq);
-            s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
-        }
-        spin_unlock_irqrestore(&card->lock, flags);
-        return 0;
-
-    case SNDCTL_DSP_SPEED:
-        get_user_ret(val, p, -EFAULT);
-        spin_lock_irqsave(&card->lock, flags);
-        if (val >= 0) {
-            if (file->f_mode & FMODE_READ) {
-                stop_adc(s);
-                s->dma_adc.ready = 0;
-                set_adc_rate(s, val);
-            }
-            if (file->f_mode & FMODE_WRITE) {
-                stop_dac(s);
-                s->dma_dac.ready = 0;
-                set_dac_rate(s, val);
-            }
-        }
-        spin_unlock_irqrestore(&card->lock, flags);
-        return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-        
-    case SNDCTL_DSP_STEREO:
-        get_user_ret(val, p, -EFAULT);
-        spin_lock_irqsave(&card->lock, flags);
-        fmtd = 0;
-        fmtm = ~0;
-        if (file->f_mode & FMODE_READ) {
-            stop_adc(s);
-            s->dma_adc.ready = 0;
-            if (val)
-                fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
-            else
-                fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
-        }
-        if (file->f_mode & FMODE_WRITE) {
-            stop_dac(s);
-            s->dma_dac.ready = 0;
-            if (val)
-                fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
-            else
-                fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
-        }
-        set_fmt(s, fmtm, fmtd);
-        spin_unlock_irqrestore(&card->lock, flags);
-        return 0;
-
-    case SNDCTL_DSP_CHANNELS:
-        get_user_ret(val, p, -EFAULT);
-        spin_lock_irqsave(&card->lock, flags);
-        if (val != 0) {
-            fmtd = 0;
-            fmtm = ~0;
-            if (file->f_mode & FMODE_READ) {
-                stop_adc(s);
-                s->dma_adc.ready = 0;
-                if (val >= 2)
-                    fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
-                else
-                    fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
-            }
-            if (file->f_mode & FMODE_WRITE) {
-                stop_dac(s);
-                s->dma_dac.ready = 0;
-                if (val >= 2)
-                    fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
-                else
-                    fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
-            }
-            set_fmt(s, fmtm, fmtd);
-        }
-        spin_unlock_irqrestore(&card->lock, flags);
-        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
-                       : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-        
-    case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-        return put_user(AFMT_U8|AFMT_S16_LE, p);
-        
-    case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-        get_user_ret(val, p, -EFAULT);
-        spin_lock_irqsave(&card->lock, flags);
-        if (val != AFMT_QUERY) {
-            fmtd = 0;
-            fmtm = ~0;
-            if (file->f_mode & FMODE_READ) {
-                stop_adc(s);
-                s->dma_adc.ready = 0;
-                if (val == AFMT_S16_LE)
-                    fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
-                else
-                    fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
-            }
-            if (file->f_mode & FMODE_WRITE) {
-                stop_dac(s);
-                s->dma_dac.ready = 0;
-                if (val == AFMT_S16_LE)
-                    fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-                else
-                    fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
-            }
-            set_fmt(s, fmtm, fmtd);
-        }
-        spin_unlock_irqrestore(&card->lock, flags);
-        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? 
-            (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
-            : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 
-                AFMT_S16_LE : 
-                AFMT_U8, 
-            p);
-        
-    case SNDCTL_DSP_POST:
-        return 0;
-
-    case SNDCTL_DSP_GETTRIGGER:
-        val = 0;
-        if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
-            val |= PCM_ENABLE_INPUT;
-        if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING)) 
-            val |= PCM_ENABLE_OUTPUT;
-        return put_user(val, p);
-        
-    case SNDCTL_DSP_SETTRIGGER:
-        get_user_ret(val, p, -EFAULT);
-        if (file->f_mode & FMODE_READ) {
-            if (val & PCM_ENABLE_INPUT) {
-                if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-                    return ret;
-                start_adc(s);
-            } else
-                stop_adc(s);
-        }
-        if (file->f_mode & FMODE_WRITE) {
-            if (val & PCM_ENABLE_OUTPUT) {
-                if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-                    return ret;
-                start_dac(s);
-            } else
-                stop_dac(s);
-        }
-        return 0;
-
-    case SNDCTL_DSP_GETOSPACE:
-        if (!(file->f_mode & FMODE_WRITE))
-            return -EINVAL;
-        if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
-            return val;
-        spin_lock_irqsave(&card->lock, flags);
-        m3_update_ptr(s);
-        abinfo.fragsize = s->dma_dac.fragsize;
-        abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
-        abinfo.fragstotal = s->dma_dac.numfrag;
-        abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
-        spin_unlock_irqrestore(&card->lock, flags);
-        return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-    case SNDCTL_DSP_GETISPACE:
-        if (!(file->f_mode & FMODE_READ))
-            return -EINVAL;
-        if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
-            return val;
-        spin_lock_irqsave(&card->lock, flags);
-        m3_update_ptr(s);
-        abinfo.fragsize = s->dma_adc.fragsize;
-        abinfo.bytes = s->dma_adc.count;
-        abinfo.fragstotal = s->dma_adc.numfrag;
-        abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
-        spin_unlock_irqrestore(&card->lock, flags);
-        return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-        
-    case SNDCTL_DSP_NONBLOCK:
-        file->f_flags |= O_NONBLOCK;
-        return 0;
-
-    case SNDCTL_DSP_GETODELAY:
-        if (!(file->f_mode & FMODE_WRITE))
-            return -EINVAL;
-        spin_lock_irqsave(&card->lock, flags);
-        m3_update_ptr(s);
-        val = s->dma_dac.count;
-        spin_unlock_irqrestore(&card->lock, flags);
-        return put_user(val, p);
-
-    case SNDCTL_DSP_GETIPTR:
-        if (!(file->f_mode & FMODE_READ))
-            return -EINVAL;
-        spin_lock_irqsave(&card->lock, flags);
-        m3_update_ptr(s);
-        cinfo.bytes = s->dma_adc.total_bytes;
-        cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
-        cinfo.ptr = s->dma_adc.hwptr;
-        if (s->dma_adc.mapped)
-            s->dma_adc.count &= s->dma_adc.fragsize-1;
-        spin_unlock_irqrestore(&card->lock, flags);
-	if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-		return -EFAULT;
-	return 0;
-
-    case SNDCTL_DSP_GETOPTR:
-        if (!(file->f_mode & FMODE_WRITE))
-            return -EINVAL;
-        spin_lock_irqsave(&card->lock, flags);
-        m3_update_ptr(s);
-        cinfo.bytes = s->dma_dac.total_bytes;
-        cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
-        cinfo.ptr = s->dma_dac.hwptr;
-        if (s->dma_dac.mapped)
-            s->dma_dac.count &= s->dma_dac.fragsize-1;
-        spin_unlock_irqrestore(&card->lock, flags);
-	if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-		return -EFAULT;
-	return 0;
-
-    case SNDCTL_DSP_GETBLKSIZE:
-        if (file->f_mode & FMODE_WRITE) {
-            if ((val = prog_dmabuf(s, 0)))
-                return val;
-            return put_user(s->dma_dac.fragsize, p);
-        }
-        if ((val = prog_dmabuf(s, 1)))
-            return val;
-        return put_user(s->dma_adc.fragsize, p);
-
-    case SNDCTL_DSP_SETFRAGMENT:
-        get_user_ret(val, p, -EFAULT);
-        spin_lock_irqsave(&card->lock, flags);
-        if (file->f_mode & FMODE_READ) {
-            s->dma_adc.ossfragshift = val & 0xffff;
-            s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-            if (s->dma_adc.ossfragshift < 4)
-                s->dma_adc.ossfragshift = 4;
-            if (s->dma_adc.ossfragshift > 15)
-                s->dma_adc.ossfragshift = 15;
-            if (s->dma_adc.ossmaxfrags < 4)
-                s->dma_adc.ossmaxfrags = 4;
-        }
-        if (file->f_mode & FMODE_WRITE) {
-            s->dma_dac.ossfragshift = val & 0xffff;
-            s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-            if (s->dma_dac.ossfragshift < 4)
-                s->dma_dac.ossfragshift = 4;
-            if (s->dma_dac.ossfragshift > 15)
-                s->dma_dac.ossfragshift = 15;
-            if (s->dma_dac.ossmaxfrags < 4)
-                s->dma_dac.ossmaxfrags = 4;
-        }
-        spin_unlock_irqrestore(&card->lock, flags);
-        return 0;
-
-    case SNDCTL_DSP_SUBDIVIDE:
-        if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-            (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-            return -EINVAL;
-                get_user_ret(val, p, -EFAULT);
-        if (val != 1 && val != 2 && val != 4)
-            return -EINVAL;
-        if (file->f_mode & FMODE_READ)
-            s->dma_adc.subdivision = val;
-        if (file->f_mode & FMODE_WRITE)
-            s->dma_dac.subdivision = val;
-        return 0;
-
-    case SOUND_PCM_READ_RATE:
-        return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
-    case SOUND_PCM_READ_CHANNELS:
-        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT) 
-                       : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
-    case SOUND_PCM_READ_BITS:
-        return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT) 
-                       : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
-
-    case SOUND_PCM_WRITE_FILTER:
-    case SNDCTL_DSP_SETSYNCRO:
-    case SOUND_PCM_READ_FILTER:
-        return -EINVAL;
-        
-    }
-    return -EINVAL;
-}
-
-static int
-allocate_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
-{
-    int order;
-
-    DPRINTK(DPSTR,"allocating for dmabuf %p\n", db);
-
-    /* 
-     * alloc as big a chunk as we can, start with 
-     * 64k 'cause we're insane.  based on order cause
-     * the amazingly complicated prog_dmabuf wants it.
-     *
-     * pci_alloc_sonsistent guarantees that it won't cross a natural
-     * boundary; the m3 hardware can't have dma cross a 64k bus
-     * address boundary.
-     */
-    for (order = 16-PAGE_SHIFT; order >= 1; order--) {
-        db->rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
-                        &(db->handle));
-        if(db->rawbuf)
-            break;
-    }
-
-    if (!db->rawbuf)
-        return 1;
-
-    DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n",
-            PAGE_SIZE<<order, order, db->rawbuf);
-
-    {
-        struct page *page, *pend;
-
-        pend = virt_to_page(db->rawbuf + (PAGE_SIZE << order) - 1);
-        for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-            SetPageReserved(page);
-    }
-
-
-    db->buforder = order;
-    db->ready = 0;
-    db->mapped = 0;
-
-    return 0;
-}
-
-static void
-nuke_lists(struct m3_card *card, struct dmabuf *db)
-{
-    m3_remove_list(card, &(card->dma_list), db->dma_index);
-    m3_remove_list(card, &(card->msrc_list), db->msrc_index);
-    db->in_lists = 0;
-}
-
-static void
-free_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
-{
-    if(db->rawbuf == NULL)
-        return;
-
-    DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db);
-
-    {
-        struct page *page, *pend;
-        pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-        for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-            ClearPageReserved(page);
-    }
-
-
-    pci_free_consistent(pci_dev, PAGE_SIZE << db->buforder,
-            db->rawbuf, db->handle);
-
-    db->rawbuf = NULL;
-    db->buforder = 0;
-    db->mapped = 0;
-    db->ready = 0;
-}
-
-static int m3_open(struct inode *inode, struct file *file)
-{
-    unsigned int minor = iminor(inode);
-    struct m3_card *c;
-    struct m3_state *s = NULL;
-    int i;
-    unsigned char fmtm = ~0, fmts = 0;
-    unsigned long flags;
-
-    /*
-     *    Scan the cards and find the channel. We only
-     *    do this at open time so it is ok
-     */
-    for(c = devs ; c != NULL ; c = c->next) {
-
-        for(i=0;i<NR_DSPS;i++) {
-
-            if(c->channels[i].dev_audio < 0)
-                continue;
-            if((c->channels[i].dev_audio ^ minor) & ~0xf)
-                continue;
-
-            s = &c->channels[i];
-            break;
-        }
-    }
-        
-    if (!s)
-        return -ENODEV;
-        
-    VALIDATE_STATE(s);
-
-    file->private_data = s;
-
-    /* wait for device to become free */
-    mutex_lock(&s->open_mutex);
-    while (s->open_mode & file->f_mode) {
-        if (file->f_flags & O_NONBLOCK) {
-            mutex_unlock(&s->open_mutex);
-            return -EWOULDBLOCK;
-        }
-        mutex_unlock(&s->open_mutex);
-        interruptible_sleep_on(&s->open_wait);
-        if (signal_pending(current))
-            return -ERESTARTSYS;
-        mutex_lock(&s->open_mutex);
-    }
-    
-    spin_lock_irqsave(&c->lock, flags);
-
-    if (file->f_mode & FMODE_READ) {
-        fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
-        if ((minor & 0xf) == SND_DEV_DSP16)
-            fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; 
-
-        s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
-        set_adc_rate(s, 8000);
-    }
-    if (file->f_mode & FMODE_WRITE) {
-        fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
-        if ((minor & 0xf) == SND_DEV_DSP16)
-            fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-
-        s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
-        set_dac_rate(s, 8000);
-    }
-    set_fmt(s, fmtm, fmts);
-    s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
-    mutex_unlock(&s->open_mutex);
-    spin_unlock_irqrestore(&c->lock, flags);
-    return nonseekable_open(inode, file);
-}
-
-static int m3_release(struct inode *inode, struct file *file)
-{
-    struct m3_state *s = (struct m3_state *)file->private_data;
-	struct m3_card *card=s->card;
-    unsigned long flags;
-
-    VALIDATE_STATE(s);
-    if (file->f_mode & FMODE_WRITE)
-        drain_dac(s, file->f_flags & O_NONBLOCK);
-
-    mutex_lock(&s->open_mutex);
-    spin_lock_irqsave(&card->lock, flags);
-
-    if (file->f_mode & FMODE_WRITE) {
-        stop_dac(s);
-        if(s->dma_dac.in_lists) {
-            m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index);
-            nuke_lists(s->card, &(s->dma_dac));
-        }
-    }
-    if (file->f_mode & FMODE_READ) {
-        stop_adc(s);
-        if(s->dma_adc.in_lists) {
-            m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index);
-            nuke_lists(s->card, &(s->dma_adc));
-        }
-    }
-        
-    s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
-    spin_unlock_irqrestore(&card->lock, flags);
-    mutex_unlock(&s->open_mutex);
-    wake_up(&s->open_wait);
-
-    return 0;
-}
-
-/*
- * Wait for the ac97 serial bus to be free.
- * return nonzero if the bus is still busy.
- */
-static int m3_ac97_wait(struct m3_card *card)
-{
-    int i = 10000;
-
-    while( (m3_inb(card, 0x30) & 1) && i--) ;
-
-    return i == 0;
-}
-
-static u16 m3_ac97_read(struct ac97_codec *codec, u8 reg)
-{
-    u16 ret = 0;
-    struct m3_card *card = codec->private_data;
-
-    spin_lock(&card->ac97_lock);
-
-    if(m3_ac97_wait(card)) {
-        printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg);
-        goto out;
-    }
-
-    m3_outb(card, 0x80 | (reg & 0x7f), 0x30);
-
-    if(m3_ac97_wait(card)) {
-        printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg);
-        goto out;
-    }
-
-    ret =  m3_inw(card, 0x32);
-    DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg);
-
-out:
-    spin_unlock(&card->ac97_lock);
-    return ret;
-}
-
-static void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
-{
-    struct m3_card *card = codec->private_data;
-
-    spin_lock(&card->ac97_lock);
-
-    if(m3_ac97_wait(card)) {
-        printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg);
-        goto out;
-    }
-    DPRINTK(DPCRAP,"writing 0x%04x  to  0x%02x\n", val, reg);
-
-    m3_outw(card, val, 0x32);
-    m3_outb(card, reg & 0x7f, 0x30);
-out:
-    spin_unlock(&card->ac97_lock);
-}
-/* OSS /dev/mixer file operation methods */
-static int m3_open_mixdev(struct inode *inode, struct file *file)
-{
-    unsigned int minor = iminor(inode);
-    struct m3_card *card = devs;
-
-    for (card = devs; card != NULL; card = card->next) {
-        if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor))
-                break;
-    }
-
-    if (!card) {
-        return -ENODEV;
-    }
-
-    file->private_data = card->ac97;
-
-    return nonseekable_open(inode, file);
-}
-
-static int m3_release_mixdev(struct inode *inode, struct file *file)
-{
-    return 0;
-}
-
-static int m3_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
-                                    unsigned long arg)
-{
-    struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
-    return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static struct file_operations m3_mixer_fops = {
-	.owner	 = THIS_MODULE,
-	.llseek  = no_llseek,
-	.ioctl	 = m3_ioctl_mixdev,
-	.open	 = m3_open_mixdev,
-	.release = m3_release_mixdev,
-};
-
-static void remote_codec_config(int io, int isremote)
-{
-    isremote = isremote ? 1 : 0;
-
-    outw(  (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,
-            io + RING_BUS_CTRL_B);
-    outw(  (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
-            io + SDO_OUT_DEST_CTRL);
-    outw(  (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
-            io + SDO_IN_DEST_CTRL);
-}
-
-/* 
- * hack, returns non zero on err 
- */
-static int try_read_vendor(struct m3_card *card)
-{
-    u16 ret;
-
-    if(m3_ac97_wait(card)) 
-        return 1;
-
-    m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);
-
-    if(m3_ac97_wait(card)) 
-        return 1;
-
-    ret =  m3_inw(card, 0x32);
-
-    return (ret == 0) || (ret == 0xffff);
-}
-
-static void m3_codec_reset(struct m3_card *card, int busywait)
-{
-    u16 dir;
-    int delay1 = 0, delay2 = 0, i;
-    int io = card->iobase;
-
-    switch (card->card_type) {
-        /*
-         * the onboard codec on the allegro seems 
-         * to want to wait a very long time before
-         * coming back to life 
-         */
-        case ESS_ALLEGRO:
-            delay1 = 50;
-            delay2 = 800;
-        break;
-        case ESS_MAESTRO3:
-        case ESS_MAESTRO3HW:
-            delay1 = 20;
-            delay2 = 500;
-        break;
-    }
-
-    for(i = 0; i < 5; i ++) {
-        dir = inw(io + GPIO_DIRECTION);
-        dir |= 0x10; /* assuming pci bus master? */
-
-        remote_codec_config(io, 0);
-
-        outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
-        udelay(20);
-
-        outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);
-        outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);
-        outw(0, io + GPIO_DATA);
-        outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
-
-        if(busywait)  {
-            mdelay(delay1);
-        } else {
-            set_current_state(TASK_UNINTERRUPTIBLE);
-            schedule_timeout((delay1 * HZ) / 1000);
-        }
-
-        outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
-        udelay(5);
-        /* ok, bring back the ac-link */
-        outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
-        outw(~0, io + GPIO_MASK);
-
-        if(busywait) {
-            mdelay(delay2);
-        } else {
-            set_current_state(TASK_UNINTERRUPTIBLE);
-            schedule_timeout((delay2 * HZ) / 1000);
-        }
-        if(! try_read_vendor(card))
-            break;
-
-        delay1 += 10;
-        delay2 += 100;
-
-        DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n",
-                delay1, delay2);
-    }
-
-#if 0
-    /* more gung-ho reset that doesn't
-     * seem to work anywhere :)
-     */
-    tmp = inw(io + RING_BUS_CTRL_A);
-    outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
-    mdelay(20);
-    outw(tmp, io + RING_BUS_CTRL_A);
-    mdelay(50);
-#endif
-}
-
-static int __devinit m3_codec_install(struct m3_card *card)
-{
-    struct ac97_codec *codec;
-
-    if ((codec = ac97_alloc_codec()) == NULL)
-        return -ENOMEM;
-
-    codec->private_data = card;
-    codec->codec_read = m3_ac97_read;
-    codec->codec_write = m3_ac97_write;
-    /* someday we should support secondary codecs.. */
-    codec->id = 0;
-
-    if (ac97_probe_codec(codec) == 0) {
-        printk(KERN_ERR PFX "codec probe failed\n");
-        ac97_release_codec(codec);
-        return -1;
-    }
-
-    if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) {
-        printk(KERN_ERR PFX "couldn't register mixer!\n");
-        ac97_release_codec(codec);
-        return -1;
-    }
-
-    card->ac97 = codec;
-
-    return 0;
-}
-
-
-#define MINISRC_LPF_LEN 10
-static u16 minisrc_lpf[MINISRC_LPF_LEN] = {
-    0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
-    0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
-};
-static void m3_assp_init(struct m3_card *card)
-{
-    int i;
-
-    /* zero kernel data */
-    for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
-        m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
-                KDATA_BASE_ADDR + i, 0);
-
-    /* zero mixer data? */
-    for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
-        m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
-                KDATA_BASE_ADDR2 + i, 0);
-
-    /* init dma pointer */
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
-            KDATA_CURRENT_DMA, 
-            KDATA_DMA_XFER0);
-
-    /* write kernel into code memory.. */
-    for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) {
-        m3_assp_write(card, MEMTYPE_INTERNAL_CODE, 
-                REV_B_CODE_MEMORY_BEGIN + i, 
-                assp_kernel_image[i]);
-    }
-
-    /*
-     * We only have this one client and we know that 0x400
-     * is free in our kernel's mem map, so lets just
-     * drop it there.  It seems that the minisrc doesn't
-     * need vectors, so we won't bother with them..
-     */
-    for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) {
-        m3_assp_write(card, MEMTYPE_INTERNAL_CODE, 
-                0x400 + i, 
-                assp_minisrc_image[i]);
-    }
-
-    /*
-     * write the coefficients for the low pass filter?
-     */
-    for(i = 0; i < MINISRC_LPF_LEN ; i++) {
-        m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
-            0x400 + MINISRC_COEF_LOC + i,
-            minisrc_lpf[i]);
-    }
-
-    m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
-        0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN,
-        0x8000);
-
-    /*
-     * the minisrc is the only thing on
-     * our task list..
-     */
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
-            KDATA_TASK0, 
-            0x400);
-
-    /*
-     * init the mixer number..
-     */
-
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-            KDATA_MIXER_TASK_NUMBER,0);
-
-    /*
-     * EXTREME KERNEL MASTER VOLUME
-     */
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-        KDATA_DAC_LEFT_VOLUME, ARB_VOLUME);
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-        KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME);
-
-    card->mixer_list.mem_addr = KDATA_MIXER_XFER0;
-    card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS;
-    card->adc1_list.mem_addr = KDATA_ADC1_XFER0;
-    card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS;
-    card->dma_list.mem_addr = KDATA_DMA_XFER0;
-    card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS;
-    card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC;
-    card->msrc_list.max = MAX_INSTANCE_MINISRC;
-}
-
-static int setup_msrc(struct m3_card *card,
-        struct assp_instance *inst, int index)
-{
-    int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + 
-            MINISRC_IN_BUFFER_SIZE / 2 +
-            1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 );
-    int address, i;
-
-    /*
-     * the revb memory map has 0x1100 through 0x1c00
-     * free.  
-     */
-
-    /*
-     * align instance address to 256 bytes so that it's
-     * shifted list address is aligned.  
-     * list address = (mem address >> 1) >> 7;
-     */
-    data_bytes = (data_bytes + 255) & ~255;
-    address = 0x1100 + ((data_bytes/2) * index);
-
-    if((address + (data_bytes/2)) >= 0x1c00) {
-        printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n",
-                data_bytes, index, address);
-        return -1;
-    }
-
-    for(i = 0; i < data_bytes/2 ; i++) 
-        m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
-                address + i, 0);
-
-    inst->code = 0x400;
-    inst->data = address;
-
-    return 0;
-}
-
-static int m3_assp_client_init(struct m3_state *s)
-{
-    setup_msrc(s->card, &(s->dac_inst), s->index * 2);
-    setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1);
-
-    return 0;
-}
-
-static void m3_amp_enable(struct m3_card *card, int enable)
-{
-    /* 
-     * this works for the reference board, have to find
-     * out about others
-     *
-     * this needs more magic for 4 speaker, but..
-     */
-    int io = card->iobase;
-    u16 gpo, polarity_port, polarity;
-
-    if(!external_amp)
-        return;
-
-    if (gpio_pin >= 0  && gpio_pin <= 15) {
-        polarity_port = 0x1000 + (0x100 * gpio_pin);
-    } else {
-        switch (card->card_type) {
-            case ESS_ALLEGRO:
-                polarity_port = 0x1800;
-                break;
-            default:
-                polarity_port = 0x1100;
-                /* Panasonic toughbook CF72 has to be different... */
-                if(card->pcidev->subsystem_vendor == 0x10F7 && card->pcidev->subsystem_device == 0x833D)
-                	polarity_port = 0x1D00;
-                break;
-        }
-    }
-
-    gpo = (polarity_port >> 8) & 0x0F;
-    polarity = polarity_port >> 12;
-    if ( enable )
-        polarity = !polarity;
-    polarity = polarity << gpo;
-    gpo = 1 << gpo;
-
-    outw(~gpo , io + GPIO_MASK);
-
-    outw( inw(io + GPIO_DIRECTION) | gpo ,
-            io + GPIO_DIRECTION);
-
-    outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) ,
-            io + GPIO_DATA);
-
-    outw(0xffff , io + GPIO_MASK);
-}
-
-static int
-maestro_config(struct m3_card *card) 
-{
-    struct pci_dev *pcidev = card->pcidev;
-    u32 n;
-    u8  t; /* makes as much sense as 'n', no? */
-
-    pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
-    n &= REDUCED_DEBOUNCE;
-    n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
-    pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
-
-    outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B);
-    pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
-    n &= ~INT_CLK_SELECT;
-    if(card->card_type >= ESS_MAESTRO3)  {
-        n &= ~INT_CLK_MULT_ENABLE; 
-        n |= INT_CLK_SRC_NOT_PCI;
-    }
-    n &=  ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 );
-    pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
-
-    if(card->card_type <= ESS_ALLEGRO) {
-        pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n);
-        n |= IN_CLK_12MHZ_SELECT;
-        pci_write_config_dword(pcidev, PCI_USER_CONFIG, n);
-    }
-
-    t = inb(card->iobase + ASSP_CONTROL_A);
-    t &= ~( DSP_CLK_36MHZ_SELECT  | ASSP_CLK_49MHZ_SELECT);
-    t |= ASSP_CLK_49MHZ_SELECT;
-    t |= ASSP_0_WS_ENABLE; 
-    outb(t, card->iobase + ASSP_CONTROL_A);
-
-    outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B); 
-
-    return 0;
-} 
-
-static void m3_enable_ints(struct m3_card *card)
-{
-    unsigned long io = card->iobase;
-
-    outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL);
-    outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
-            io + ASSP_CONTROL_C);
-}
-
-static struct file_operations m3_audio_fops = {
-	.owner	 = THIS_MODULE,
-	.llseek	 = no_llseek,
-	.read	 = m3_read,
-	.write	 = m3_write,
-	.poll	 = m3_poll,
-	.ioctl	 = m3_ioctl,
-	.mmap	 = m3_mmap,
-	.open	 = m3_open,
-	.release = m3_release,
-};
-
-#ifdef CONFIG_PM
-static int alloc_dsp_suspendmem(struct m3_card *card)
-{
-    int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
-
-    if( (card->suspend_mem = vmalloc(len)) == NULL)
-        return 1;
-
-    return 0;
-}
-
-#else
-#define alloc_dsp_suspendmem(args...) 0
-#endif
-
-/*
- * great day!  this function is ugly as hell.
- */
-static int __devinit m3_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
-    u32 n;
-    int i;
-    struct m3_card *card = NULL;
-    int ret = 0;
-    int card_type = pci_id->driver_data;
-
-    DPRINTK(DPMOD, "in maestro_install\n");
-
-    if (pci_enable_device(pci_dev))
-        return -EIO;
-
-    if (pci_set_dma_mask(pci_dev, M3_PCI_DMA_MASK)) {
-        printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n");
-        return -ENODEV;
-    }
-        
-    pci_set_master(pci_dev);
-
-    if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) {
-        printk(KERN_WARNING PFX "out of memory\n");
-        return -ENOMEM;
-    }
-    memset(card, 0, sizeof(struct m3_card));
-    card->pcidev = pci_dev;
-    init_waitqueue_head(&card->suspend_queue);
-
-    if ( ! request_region(pci_resource_start(pci_dev, 0),
-                pci_resource_len (pci_dev, 0), M3_MODULE_NAME)) {
-
-        printk(KERN_WARNING PFX "unable to reserve I/O space.\n");
-        ret = -EBUSY;
-        goto out;
-    }
-
-    card->iobase = pci_resource_start(pci_dev, 0);
-
-    if(alloc_dsp_suspendmem(card)) {
-        printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n",
-                REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
-        ret = -ENOMEM;
-        goto out;
-    }
-
-    card->card_type = card_type;
-    card->irq = pci_dev->irq;
-    card->next = devs;
-    card->magic = M3_CARD_MAGIC;
-    spin_lock_init(&card->lock);
-    spin_lock_init(&card->ac97_lock);
-    devs = card;
-    for(i = 0; i<NR_DSPS; i++) {
-        struct m3_state *s = &(card->channels[i]);
-        s->dev_audio = -1;
-    }
-
-    printk(KERN_INFO PFX "Configuring ESS %s found at IO 0x%04X IRQ %d\n", 
-        card_names[card->card_type], card->iobase, card->irq);
-
-    pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &n);
-    printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n); 
-
-    maestro_config(card);
-    m3_assp_halt(card);
-
-    m3_codec_reset(card, 0);
-
-    if(m3_codec_install(card))  {
-        ret = -EIO; 
-        goto out;
-    }
-
-    m3_assp_init(card);
-    m3_amp_enable(card, 1);
-    
-    for(i=0;i<NR_DSPS;i++) {
-        struct m3_state *s=&card->channels[i];
-
-        s->index = i;
-
-        s->card = card;
-        init_waitqueue_head(&s->dma_adc.wait);
-        init_waitqueue_head(&s->dma_dac.wait);
-        init_waitqueue_head(&s->open_wait);
-        mutex_init(&(s->open_mutex));
-        s->magic = M3_STATE_MAGIC;
-
-        m3_assp_client_init(s);
-        
-        if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
-            printk(KERN_WARNING PFX "initing a dsp device that is already in use?\n");
-        /* register devices */
-        if ((s->dev_audio = register_sound_dsp(&m3_audio_fops, -1)) < 0) {
-            break;
-        }
-
-        if( allocate_dmabuf(card->pcidev, &(s->dma_adc)) ||
-                allocate_dmabuf(card->pcidev, &(s->dma_dac)))  { 
-            ret = -ENOMEM;
-            goto out;
-        }
-    }
-    
-    if(request_irq(card->irq, m3_interrupt, IRQF_SHARED, card_names[card->card_type], card)) {
-
-        printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq);
-
-        ret = -EIO;
-        goto out;
-    }
-
-    pci_set_drvdata(pci_dev, card);
-    
-    m3_enable_ints(card);
-    m3_assp_continue(card);
-
-out:
-    if(ret) {
-        if(card->iobase)
-            release_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
-        vfree(card->suspend_mem);
-        if(card->ac97) {
-            unregister_sound_mixer(card->ac97->dev_mixer);
-            kfree(card->ac97);
-        }
-        for(i=0;i<NR_DSPS;i++)
-        {
-            struct m3_state *s = &card->channels[i];
-            if(s->dev_audio != -1)
-                unregister_sound_dsp(s->dev_audio);
-        }
-        kfree(card);
-    }
-
-    return ret; 
-}
-
-static void m3_remove(struct pci_dev *pci_dev)
-{
-    struct m3_card *card;
-
-    unregister_reboot_notifier(&m3_reboot_nb);
-
-    while ((card = devs)) {
-        int i;
-        devs = devs->next;
-    
-        free_irq(card->irq, card);
-        unregister_sound_mixer(card->ac97->dev_mixer);
-        kfree(card->ac97);
-
-        for(i=0;i<NR_DSPS;i++)
-        {
-            struct m3_state *s = &card->channels[i];
-            if(s->dev_audio < 0)
-                continue;
-
-            unregister_sound_dsp(s->dev_audio);
-            free_dmabuf(card->pcidev, &s->dma_adc);
-            free_dmabuf(card->pcidev, &s->dma_dac);
-        }
-
-        release_region(card->iobase, 256);
-        vfree(card->suspend_mem);
-        kfree(card);
-    }
-    devs = NULL;
-}
-
-/*
- * some bioses like the sound chip to be powered down
- * at shutdown.  We're just calling _suspend to
- * achieve that..
- */
-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf)
-{
-    struct m3_card *card;
-
-    DPRINTK(DPMOD, "notifier suspending all cards\n");
-
-    for(card = devs; card != NULL; card = card->next) {
-        if(!card->in_suspend)
-            m3_suspend(card->pcidev, PMSG_SUSPEND); /* XXX legal? */
-    }
-    return 0;
-}
-
-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state)
-{
-    unsigned long flags;
-    int i;
-    struct m3_card *card = pci_get_drvdata(pci_dev);
-
-    /* must be a better way.. */
-	spin_lock_irqsave(&card->lock, flags);
-
-    DPRINTK(DPMOD, "pm in dev %p\n",card);
-
-    for(i=0;i<NR_DSPS;i++) {
-        struct m3_state *s = &card->channels[i];
-
-        if(s->dev_audio == -1)
-            continue;
-
-        DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i);
-        stop_dac(s);
-        stop_adc(s);
-    }
-
-    mdelay(10); /* give the assp a chance to idle.. */
-
-    m3_assp_halt(card);
-
-    if(card->suspend_mem) {
-        int index = 0;
-
-        DPRINTK(DPMOD, "saving code\n");
-        for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
-            card->suspend_mem[index++] = 
-                m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i);
-        DPRINTK(DPMOD, "saving data\n");
-        for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
-            card->suspend_mem[index++] = 
-                m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i);
-    }
-
-    DPRINTK(DPMOD, "powering down apci regs\n");
-    m3_outw(card, 0xffff, 0x54);
-    m3_outw(card, 0xffff, 0x56);
-
-    card->in_suspend = 1;
-
-    spin_unlock_irqrestore(&card->lock, flags);
-
-    return 0;
-}
-
-static int m3_resume(struct pci_dev *pci_dev)
-{
-    unsigned long flags;
-    int index;
-    int i;
-    struct m3_card *card = pci_get_drvdata(pci_dev);
-
-	spin_lock_irqsave(&card->lock, flags);
-    card->in_suspend = 0;
-
-    DPRINTK(DPMOD, "resuming\n");
-
-    /* first lets just bring everything back. .*/
-
-    DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card);
-    m3_outw(card, 0, 0x54);
-    m3_outw(card, 0, 0x56);
-
-    DPRINTK(DPMOD, "restoring pci configs and reseting codec\n");
-    maestro_config(card);
-    m3_assp_halt(card);
-    m3_codec_reset(card, 1);
-
-    DPRINTK(DPMOD, "restoring dsp code card\n");
-    index = 0;
-    for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
-        m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i, 
-            card->suspend_mem[index++]);
-    for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
-        m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i, 
-            card->suspend_mem[index++]);
-
-     /* tell the dma engine to restart itself */
-    m3_assp_write(card, MEMTYPE_INTERNAL_DATA, 
-        KDATA_DMA_ACTIVE, 0);
-
-    DPRINTK(DPMOD, "resuming dsp\n");
-    m3_assp_continue(card);
-
-    DPRINTK(DPMOD, "enabling ints\n");
-    m3_enable_ints(card);
-
-    /* bring back the old school flavor */
-    for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) {
-        int state = card->ac97->mixer_state[i];
-        if (!supported_mixer(card->ac97, i)) 
-                continue;
-
-        card->ac97->write_mixer(card->ac97, i, 
-                state & 0xff, (state >> 8) & 0xff);
-    }
-
-    m3_amp_enable(card, 1);
-
-    /* 
-     * now we flip on the music 
-     */
-    for(i=0;i<NR_DSPS;i++) {
-        struct m3_state *s = &card->channels[i];
-        if(s->dev_audio == -1)
-            continue;
-        /*
-         * db->ready makes it so these guys can be
-         * called unconditionally..
-         */
-        DPRINTK(DPMOD, "turning on dacs ind %d\n",i);
-        start_dac(s);    
-        start_adc(s);    
-    }
-
-    spin_unlock_irqrestore(&card->lock, flags);
-
-    /* 
-     * all right, we think things are ready, 
-     * wake up people who were using the device 
-     * when we suspended
-     */
-    wake_up(&card->suspend_queue);
-
-    return 0;
-}
-
-MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
-MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver");
-MODULE_LICENSE("GPL");
-
-#ifdef M_DEBUG
-module_param(debug, int, 0);
-#endif
-module_param(external_amp, int, 0);
-module_param(gpio_pin, int, 0);
-
-static struct pci_driver m3_pci_driver = {
-	.name	  = "ess_m3_audio",
-	.id_table = m3_id_table,
-	.probe	  = m3_probe,
-	.remove	  = m3_remove,
-	.suspend  = m3_suspend,
-	.resume	  = m3_resume,
-};
-
-static int __init m3_init_module(void)
-{
-    printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n");
-
-    if (register_reboot_notifier(&m3_reboot_nb)) {
-        printk(KERN_WARNING PFX "reboot notifier registration failed\n");
-        return -ENODEV; /* ? */
-    }
-
-    if (pci_register_driver(&m3_pci_driver)) {
-        unregister_reboot_notifier(&m3_reboot_nb);
-        return -ENODEV;
-    }
-    return 0;
-}
-
-static void __exit m3_cleanup_module(void)
-{
-    pci_unregister_driver(&m3_pci_driver);
-}
-
-module_init(m3_init_module);
-module_exit(m3_cleanup_module);
-
-void check_suspend(struct m3_card *card)
-{
-    DECLARE_WAITQUEUE(wait, current);
-
-    if(!card->in_suspend) 
-        return;
-
-    card->in_suspend++;
-    add_wait_queue(&card->suspend_queue, &wait);
-    set_current_state(TASK_UNINTERRUPTIBLE);
-    schedule();
-    remove_wait_queue(&card->suspend_queue, &wait);
-    set_current_state(TASK_RUNNING);
-}
diff --git a/sound/oss/maestro3.h b/sound/oss/maestro3.h
deleted file mode 100644
index dde2986..0000000
--- a/sound/oss/maestro3.h
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
- *      ESS Technology allegro audio driver.
- *
- *      Copyright (C) 1992-2000  Don Kim (don.kim@esstech.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *      Hacked for the maestro3 driver by zab
- */
-
-// Allegro PCI configuration registers
-#define PCI_LEGACY_AUDIO_CTRL   0x40
-#define SOUND_BLASTER_ENABLE    0x00000001
-#define FM_SYNTHESIS_ENABLE     0x00000002
-#define GAME_PORT_ENABLE        0x00000004
-#define MPU401_IO_ENABLE        0x00000008
-#define MPU401_IRQ_ENABLE       0x00000010
-#define ALIAS_10BIT_IO          0x00000020
-#define SB_DMA_MASK             0x000000C0
-#define SB_DMA_0                0x00000040
-#define SB_DMA_1                0x00000040
-#define SB_DMA_R                0x00000080
-#define SB_DMA_3                0x000000C0
-#define SB_IRQ_MASK             0x00000700
-#define SB_IRQ_5                0x00000000
-#define SB_IRQ_7                0x00000100
-#define SB_IRQ_9                0x00000200
-#define SB_IRQ_10               0x00000300
-#define MIDI_IRQ_MASK           0x00003800
-#define SERIAL_IRQ_ENABLE       0x00004000
-#define DISABLE_LEGACY          0x00008000
-
-#define PCI_ALLEGRO_CONFIG      0x50
-#define SB_ADDR_240             0x00000004
-#define MPU_ADDR_MASK           0x00000018
-#define MPU_ADDR_330            0x00000000
-#define MPU_ADDR_300            0x00000008
-#define MPU_ADDR_320            0x00000010
-#define MPU_ADDR_340            0x00000018
-#define USE_PCI_TIMING          0x00000040
-#define POSTED_WRITE_ENABLE     0x00000080
-#define DMA_POLICY_MASK         0x00000700
-#define DMA_DDMA                0x00000000
-#define DMA_TDMA                0x00000100
-#define DMA_PCPCI               0x00000200
-#define DMA_WBDMA16             0x00000400
-#define DMA_WBDMA4              0x00000500
-#define DMA_WBDMA2              0x00000600
-#define DMA_WBDMA1              0x00000700
-#define DMA_SAFE_GUARD          0x00000800
-#define HI_PERF_GP_ENABLE       0x00001000
-#define PIC_SNOOP_MODE_0        0x00002000
-#define PIC_SNOOP_MODE_1        0x00004000
-#define SOUNDBLASTER_IRQ_MASK   0x00008000
-#define RING_IN_ENABLE          0x00010000
-#define SPDIF_TEST_MODE         0x00020000
-#define CLK_MULT_MODE_SELECT_2  0x00040000
-#define EEPROM_WRITE_ENABLE     0x00080000
-#define CODEC_DIR_IN            0x00100000
-#define HV_BUTTON_FROM_GD       0x00200000
-#define REDUCED_DEBOUNCE        0x00400000
-#define HV_CTRL_ENABLE          0x00800000
-#define SPDIF_ENABLE            0x01000000
-#define CLK_DIV_SELECT          0x06000000
-#define CLK_DIV_BY_48           0x00000000
-#define CLK_DIV_BY_49           0x02000000
-#define CLK_DIV_BY_50           0x04000000
-#define CLK_DIV_RESERVED        0x06000000
-#define PM_CTRL_ENABLE          0x08000000
-#define CLK_MULT_MODE_SELECT    0x30000000
-#define CLK_MULT_MODE_SHIFT     28
-#define CLK_MULT_MODE_0         0x00000000
-#define CLK_MULT_MODE_1         0x10000000
-#define CLK_MULT_MODE_2         0x20000000
-#define CLK_MULT_MODE_3         0x30000000
-#define INT_CLK_SELECT          0x40000000
-#define INT_CLK_MULT_RESET      0x80000000
-
-// M3
-#define INT_CLK_SRC_NOT_PCI     0x00100000
-#define INT_CLK_MULT_ENABLE     0x80000000
-
-#define PCI_ACPI_CONTROL        0x54
-#define PCI_ACPI_D0             0x00000000
-#define PCI_ACPI_D1             0xB4F70000
-#define PCI_ACPI_D2             0xB4F7B4F7
-
-#define PCI_USER_CONFIG         0x58
-#define EXT_PCI_MASTER_ENABLE   0x00000001
-#define SPDIF_OUT_SELECT        0x00000002
-#define TEST_PIN_DIR_CTRL       0x00000004
-#define AC97_CODEC_TEST         0x00000020
-#define TRI_STATE_BUFFER        0x00000080
-#define IN_CLK_12MHZ_SELECT     0x00000100
-#define MULTI_FUNC_DISABLE      0x00000200
-#define EXT_MASTER_PAIR_SEL     0x00000400
-#define PCI_MASTER_SUPPORT      0x00000800
-#define STOP_CLOCK_ENABLE       0x00001000
-#define EAPD_DRIVE_ENABLE       0x00002000
-#define REQ_TRI_STATE_ENABLE    0x00004000
-#define REQ_LOW_ENABLE          0x00008000
-#define MIDI_1_ENABLE           0x00010000
-#define MIDI_2_ENABLE           0x00020000
-#define SB_AUDIO_SYNC           0x00040000
-#define HV_CTRL_TEST            0x00100000
-#define SOUNDBLASTER_TEST       0x00400000
-
-#define PCI_USER_CONFIG_C       0x5C
-
-#define PCI_DDMA_CTRL           0x60
-#define DDMA_ENABLE             0x00000001
-
-
-// Allegro registers
-#define HOST_INT_CTRL           0x18
-#define SB_INT_ENABLE           0x0001
-#define MPU401_INT_ENABLE       0x0002
-#define ASSP_INT_ENABLE         0x0010
-#define RING_INT_ENABLE         0x0020
-#define HV_INT_ENABLE           0x0040
-#define CLKRUN_GEN_ENABLE       0x0100
-#define HV_CTRL_TO_PME          0x0400
-#define SOFTWARE_RESET_ENABLE   0x8000
-
-/*
- * should be using the above defines, probably.
- */
-#define REGB_ENABLE_RESET               0x01
-#define REGB_STOP_CLOCK                 0x10
-
-#define HOST_INT_STATUS         0x1A
-#define SB_INT_PENDING          0x01
-#define MPU401_INT_PENDING      0x02
-#define ASSP_INT_PENDING        0x10
-#define RING_INT_PENDING        0x20
-#define HV_INT_PENDING          0x40
-
-#define HARDWARE_VOL_CTRL       0x1B
-#define SHADOW_MIX_REG_VOICE    0x1C
-#define HW_VOL_COUNTER_VOICE    0x1D
-#define SHADOW_MIX_REG_MASTER   0x1E
-#define HW_VOL_COUNTER_MASTER   0x1F
-
-#define CODEC_COMMAND           0x30
-#define CODEC_READ_B            0x80
-
-#define CODEC_STATUS            0x30
-#define CODEC_BUSY_B            0x01
-
-#define CODEC_DATA              0x32
-
-#define RING_BUS_CTRL_A         0x36
-#define RAC_PME_ENABLE          0x0100
-#define RAC_SDFS_ENABLE         0x0200
-#define LAC_PME_ENABLE          0x0400
-#define LAC_SDFS_ENABLE         0x0800
-#define SERIAL_AC_LINK_ENABLE   0x1000
-#define IO_SRAM_ENABLE          0x2000
-#define IIS_INPUT_ENABLE        0x8000
-
-#define RING_BUS_CTRL_B         0x38
-#define SECOND_CODEC_ID_MASK    0x0003
-#define SPDIF_FUNC_ENABLE       0x0010
-#define SECOND_AC_ENABLE        0x0020
-#define SB_MODULE_INTF_ENABLE   0x0040
-#define SSPE_ENABLE             0x0040
-#define M3I_DOCK_ENABLE         0x0080
-
-#define SDO_OUT_DEST_CTRL       0x3A
-#define COMMAND_ADDR_OUT        0x0003
-#define PCM_LR_OUT_LOCAL        0x0000
-#define PCM_LR_OUT_REMOTE       0x0004
-#define PCM_LR_OUT_MUTE         0x0008
-#define PCM_LR_OUT_BOTH         0x000C
-#define LINE1_DAC_OUT_LOCAL     0x0000
-#define LINE1_DAC_OUT_REMOTE    0x0010
-#define LINE1_DAC_OUT_MUTE      0x0020
-#define LINE1_DAC_OUT_BOTH      0x0030
-#define PCM_CLS_OUT_LOCAL       0x0000
-#define PCM_CLS_OUT_REMOTE      0x0040
-#define PCM_CLS_OUT_MUTE        0x0080
-#define PCM_CLS_OUT_BOTH        0x00C0
-#define PCM_RLF_OUT_LOCAL       0x0000
-#define PCM_RLF_OUT_REMOTE      0x0100
-#define PCM_RLF_OUT_MUTE        0x0200
-#define PCM_RLF_OUT_BOTH        0x0300
-#define LINE2_DAC_OUT_LOCAL     0x0000
-#define LINE2_DAC_OUT_REMOTE    0x0400
-#define LINE2_DAC_OUT_MUTE      0x0800
-#define LINE2_DAC_OUT_BOTH      0x0C00
-#define HANDSET_OUT_LOCAL       0x0000
-#define HANDSET_OUT_REMOTE      0x1000
-#define HANDSET_OUT_MUTE        0x2000
-#define HANDSET_OUT_BOTH        0x3000
-#define IO_CTRL_OUT_LOCAL       0x0000
-#define IO_CTRL_OUT_REMOTE      0x4000
-#define IO_CTRL_OUT_MUTE        0x8000
-#define IO_CTRL_OUT_BOTH        0xC000
-
-#define SDO_IN_DEST_CTRL        0x3C
-#define STATUS_ADDR_IN          0x0003
-#define PCM_LR_IN_LOCAL         0x0000
-#define PCM_LR_IN_REMOTE        0x0004
-#define PCM_LR_RESERVED         0x0008
-#define PCM_LR_IN_BOTH          0x000C
-#define LINE1_ADC_IN_LOCAL      0x0000
-#define LINE1_ADC_IN_REMOTE     0x0010
-#define LINE1_ADC_IN_MUTE       0x0020
-#define MIC_ADC_IN_LOCAL        0x0000
-#define MIC_ADC_IN_REMOTE       0x0040
-#define MIC_ADC_IN_MUTE         0x0080
-#define LINE2_DAC_IN_LOCAL      0x0000
-#define LINE2_DAC_IN_REMOTE     0x0400
-#define LINE2_DAC_IN_MUTE       0x0800
-#define HANDSET_IN_LOCAL        0x0000
-#define HANDSET_IN_REMOTE       0x1000
-#define HANDSET_IN_MUTE         0x2000
-#define IO_STATUS_IN_LOCAL      0x0000
-#define IO_STATUS_IN_REMOTE     0x4000
-
-#define SPDIF_IN_CTRL           0x3E
-#define SPDIF_IN_ENABLE         0x0001
-
-#define GPIO_DATA               0x60
-#define GPIO_DATA_MASK          0x0FFF
-#define GPIO_HV_STATUS          0x3000
-#define GPIO_PME_STATUS         0x4000
-
-#define GPIO_MASK               0x64
-#define GPIO_DIRECTION          0x68
-#define GPO_PRIMARY_AC97        0x0001
-#define GPI_LINEOUT_SENSE       0x0004
-#define GPO_SECONDARY_AC97      0x0008
-#define GPI_VOL_DOWN            0x0010
-#define GPI_VOL_UP              0x0020
-#define GPI_IIS_CLK             0x0040
-#define GPI_IIS_LRCLK           0x0080
-#define GPI_IIS_DATA            0x0100
-#define GPI_DOCKING_STATUS      0x0100
-#define GPI_HEADPHONE_SENSE     0x0200
-#define GPO_EXT_AMP_SHUTDOWN    0x1000
-
-// M3
-#define GPO_M3_EXT_AMP_SHUTDN   0x0002
-
-#define ASSP_INDEX_PORT         0x80
-#define ASSP_MEMORY_PORT        0x82
-#define ASSP_DATA_PORT          0x84
-
-#define MPU401_DATA_PORT        0x98
-#define MPU401_STATUS_PORT      0x99
-
-#define CLK_MULT_DATA_PORT      0x9C
-
-#define ASSP_CONTROL_A          0xA2
-#define ASSP_0_WS_ENABLE        0x01
-#define ASSP_CTRL_A_RESERVED1   0x02
-#define ASSP_CTRL_A_RESERVED2   0x04
-#define ASSP_CLK_49MHZ_SELECT   0x08
-#define FAST_PLU_ENABLE         0x10
-#define ASSP_CTRL_A_RESERVED3   0x20
-#define DSP_CLK_36MHZ_SELECT    0x40
-
-#define ASSP_CONTROL_B          0xA4
-#define RESET_ASSP              0x00
-#define RUN_ASSP                0x01
-#define ENABLE_ASSP_CLOCK       0x00
-#define STOP_ASSP_CLOCK         0x10
-#define RESET_TOGGLE            0x40
-
-#define ASSP_CONTROL_C          0xA6
-#define ASSP_HOST_INT_ENABLE    0x01
-#define FM_ADDR_REMAP_DISABLE   0x02
-#define HOST_WRITE_PORT_ENABLE  0x08
-
-#define ASSP_HOST_INT_STATUS    0xAC
-#define DSP2HOST_REQ_PIORECORD  0x01
-#define DSP2HOST_REQ_I2SRATE    0x02
-#define DSP2HOST_REQ_TIMER      0x04
-
-// AC97 registers
-// XXX fix this crap up
-/*#define AC97_RESET              0x00*/
-
-#define AC97_VOL_MUTE_B         0x8000
-#define AC97_VOL_M              0x1F
-#define AC97_LEFT_VOL_S         8
-
-#define AC97_MASTER_VOL         0x02
-#define AC97_LINE_LEVEL_VOL     0x04
-#define AC97_MASTER_MONO_VOL    0x06
-#define AC97_PC_BEEP_VOL        0x0A
-#define AC97_PC_BEEP_VOL_M      0x0F
-#define AC97_SROUND_MASTER_VOL  0x38
-#define AC97_PC_BEEP_VOL_S      1
-
-/*#define AC97_PHONE_VOL          0x0C
-#define AC97_MIC_VOL            0x0E*/
-#define AC97_MIC_20DB_ENABLE    0x40
-
-/*#define AC97_LINEIN_VOL         0x10
-#define AC97_CD_VOL             0x12
-#define AC97_VIDEO_VOL          0x14
-#define AC97_AUX_VOL            0x16*/
-#define AC97_PCM_OUT_VOL        0x18
-/*#define AC97_RECORD_SELECT      0x1A*/
-#define AC97_RECORD_MIC         0x00
-#define AC97_RECORD_CD          0x01
-#define AC97_RECORD_VIDEO       0x02
-#define AC97_RECORD_AUX         0x03
-#define AC97_RECORD_MONO_MUX    0x02
-#define AC97_RECORD_DIGITAL     0x03
-#define AC97_RECORD_LINE        0x04
-#define AC97_RECORD_STEREO      0x05
-#define AC97_RECORD_MONO        0x06
-#define AC97_RECORD_PHONE       0x07
-
-/*#define AC97_RECORD_GAIN        0x1C*/
-#define AC97_RECORD_VOL_M       0x0F
-
-/*#define AC97_GENERAL_PURPOSE    0x20*/
-#define AC97_POWER_DOWN_CTRL    0x26
-#define AC97_ADC_READY          0x0001
-#define AC97_DAC_READY          0x0002
-#define AC97_ANALOG_READY       0x0004
-#define AC97_VREF_ON            0x0008
-#define AC97_PR0                0x0100
-#define AC97_PR1                0x0200
-#define AC97_PR2                0x0400
-#define AC97_PR3                0x0800
-#define AC97_PR4                0x1000
-
-#define AC97_RESERVED1          0x28
-
-#define AC97_VENDOR_TEST        0x5A
-
-#define AC97_CLOCK_DELAY        0x5C
-#define AC97_LINEOUT_MUX_SEL    0x0001
-#define AC97_MONO_MUX_SEL       0x0002
-#define AC97_CLOCK_DELAY_SEL    0x1F
-#define AC97_DAC_CDS_SHIFT      6
-#define AC97_ADC_CDS_SHIFT      11
-
-#define AC97_MULTI_CHANNEL_SEL  0x74
-
-/*#define AC97_VENDOR_ID1         0x7C
-#define AC97_VENDOR_ID2         0x7E*/
-
-/*
- * ASSP control regs
- */
-#define DSP_PORT_TIMER_COUNT    0x06
-
-#define DSP_PORT_MEMORY_INDEX   0x80
-
-#define DSP_PORT_MEMORY_TYPE    0x82
-#define MEMTYPE_INTERNAL_CODE   0x0002
-#define MEMTYPE_INTERNAL_DATA   0x0003
-#define MEMTYPE_MASK            0x0003
-
-#define DSP_PORT_MEMORY_DATA    0x84
-
-#define DSP_PORT_CONTROL_REG_A  0xA2
-#define DSP_PORT_CONTROL_REG_B  0xA4
-#define DSP_PORT_CONTROL_REG_C  0xA6
-
-#define REV_A_CODE_MEMORY_BEGIN         0x0000
-#define REV_A_CODE_MEMORY_END           0x0FFF
-#define REV_A_CODE_MEMORY_UNIT_LENGTH   0x0040
-#define REV_A_CODE_MEMORY_LENGTH        (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1)
-
-#define REV_B_CODE_MEMORY_BEGIN         0x0000
-#define REV_B_CODE_MEMORY_END           0x0BFF
-#define REV_B_CODE_MEMORY_UNIT_LENGTH   0x0040
-#define REV_B_CODE_MEMORY_LENGTH        (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
-
-#define REV_A_DATA_MEMORY_BEGIN         0x1000
-#define REV_A_DATA_MEMORY_END           0x2FFF
-#define REV_A_DATA_MEMORY_UNIT_LENGTH   0x0080
-#define REV_A_DATA_MEMORY_LENGTH        (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
-
-#define REV_B_DATA_MEMORY_BEGIN         0x1000
-#define REV_B_DATA_MEMORY_END           0x2BFF
-#define REV_B_DATA_MEMORY_UNIT_LENGTH   0x0080
-#define REV_B_DATA_MEMORY_LENGTH        (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
-
-
-#define NUM_UNITS_KERNEL_CODE          16
-#define NUM_UNITS_KERNEL_DATA           2
-
-#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
-#define NUM_UNITS_KERNEL_DATA_WITH_HSP  5
-
-/*
- * Kernel data layout
- */
-
-#define DP_SHIFT_COUNT                  7
-
-#define KDATA_BASE_ADDR                 0x1000
-#define KDATA_BASE_ADDR2                0x1080
-
-#define KDATA_TASK0                     (KDATA_BASE_ADDR + 0x0000)
-#define KDATA_TASK1                     (KDATA_BASE_ADDR + 0x0001)
-#define KDATA_TASK2                     (KDATA_BASE_ADDR + 0x0002)
-#define KDATA_TASK3                     (KDATA_BASE_ADDR + 0x0003)
-#define KDATA_TASK4                     (KDATA_BASE_ADDR + 0x0004)
-#define KDATA_TASK5                     (KDATA_BASE_ADDR + 0x0005)
-#define KDATA_TASK6                     (KDATA_BASE_ADDR + 0x0006)
-#define KDATA_TASK7                     (KDATA_BASE_ADDR + 0x0007)
-#define KDATA_TASK_ENDMARK              (KDATA_BASE_ADDR + 0x0008)
-
-#define KDATA_CURRENT_TASK              (KDATA_BASE_ADDR + 0x0009)
-#define KDATA_TASK_SWITCH               (KDATA_BASE_ADDR + 0x000A)
-
-#define KDATA_INSTANCE0_POS3D           (KDATA_BASE_ADDR + 0x000B)
-#define KDATA_INSTANCE1_POS3D           (KDATA_BASE_ADDR + 0x000C)
-#define KDATA_INSTANCE2_POS3D           (KDATA_BASE_ADDR + 0x000D)
-#define KDATA_INSTANCE3_POS3D           (KDATA_BASE_ADDR + 0x000E)
-#define KDATA_INSTANCE4_POS3D           (KDATA_BASE_ADDR + 0x000F)
-#define KDATA_INSTANCE5_POS3D           (KDATA_BASE_ADDR + 0x0010)
-#define KDATA_INSTANCE6_POS3D           (KDATA_BASE_ADDR + 0x0011)
-#define KDATA_INSTANCE7_POS3D           (KDATA_BASE_ADDR + 0x0012)
-#define KDATA_INSTANCE8_POS3D           (KDATA_BASE_ADDR + 0x0013)
-#define KDATA_INSTANCE_POS3D_ENDMARK    (KDATA_BASE_ADDR + 0x0014)
-
-#define KDATA_INSTANCE0_SPKVIRT         (KDATA_BASE_ADDR + 0x0015)
-#define KDATA_INSTANCE_SPKVIRT_ENDMARK  (KDATA_BASE_ADDR + 0x0016)
-
-#define KDATA_INSTANCE0_SPDIF           (KDATA_BASE_ADDR + 0x0017)
-#define KDATA_INSTANCE_SPDIF_ENDMARK    (KDATA_BASE_ADDR + 0x0018)
-
-#define KDATA_INSTANCE0_MODEM           (KDATA_BASE_ADDR + 0x0019)
-#define KDATA_INSTANCE_MODEM_ENDMARK    (KDATA_BASE_ADDR + 0x001A)
-
-#define KDATA_INSTANCE0_SRC             (KDATA_BASE_ADDR + 0x001B)
-#define KDATA_INSTANCE1_SRC             (KDATA_BASE_ADDR + 0x001C)
-#define KDATA_INSTANCE_SRC_ENDMARK      (KDATA_BASE_ADDR + 0x001D)
-
-#define KDATA_INSTANCE0_MINISRC         (KDATA_BASE_ADDR + 0x001E)
-#define KDATA_INSTANCE1_MINISRC         (KDATA_BASE_ADDR + 0x001F)
-#define KDATA_INSTANCE2_MINISRC         (KDATA_BASE_ADDR + 0x0020)
-#define KDATA_INSTANCE3_MINISRC         (KDATA_BASE_ADDR + 0x0021)
-#define KDATA_INSTANCE_MINISRC_ENDMARK  (KDATA_BASE_ADDR + 0x0022)
-
-#define KDATA_INSTANCE0_CPYTHRU         (KDATA_BASE_ADDR + 0x0023)
-#define KDATA_INSTANCE1_CPYTHRU         (KDATA_BASE_ADDR + 0x0024)
-#define KDATA_INSTANCE_CPYTHRU_ENDMARK  (KDATA_BASE_ADDR + 0x0025)
-
-#define KDATA_CURRENT_DMA               (KDATA_BASE_ADDR + 0x0026)
-#define KDATA_DMA_SWITCH                (KDATA_BASE_ADDR + 0x0027)
-#define KDATA_DMA_ACTIVE                (KDATA_BASE_ADDR + 0x0028)
-
-#define KDATA_DMA_XFER0                 (KDATA_BASE_ADDR + 0x0029)
-#define KDATA_DMA_XFER1                 (KDATA_BASE_ADDR + 0x002A)
-#define KDATA_DMA_XFER2                 (KDATA_BASE_ADDR + 0x002B)
-#define KDATA_DMA_XFER3                 (KDATA_BASE_ADDR + 0x002C)
-#define KDATA_DMA_XFER4                 (KDATA_BASE_ADDR + 0x002D)
-#define KDATA_DMA_XFER5                 (KDATA_BASE_ADDR + 0x002E)
-#define KDATA_DMA_XFER6                 (KDATA_BASE_ADDR + 0x002F)
-#define KDATA_DMA_XFER7                 (KDATA_BASE_ADDR + 0x0030)
-#define KDATA_DMA_XFER8                 (KDATA_BASE_ADDR + 0x0031)
-#define KDATA_DMA_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0032)
-
-#define KDATA_I2S_SAMPLE_COUNT          (KDATA_BASE_ADDR + 0x0033)
-#define KDATA_I2S_INT_METER             (KDATA_BASE_ADDR + 0x0034)
-#define KDATA_I2S_ACTIVE                (KDATA_BASE_ADDR + 0x0035)
-
-#define KDATA_TIMER_COUNT_RELOAD        (KDATA_BASE_ADDR + 0x0036)
-#define KDATA_TIMER_COUNT_CURRENT       (KDATA_BASE_ADDR + 0x0037)
-
-#define KDATA_HALT_SYNCH_CLIENT         (KDATA_BASE_ADDR + 0x0038)
-#define KDATA_HALT_SYNCH_DMA            (KDATA_BASE_ADDR + 0x0039)
-#define KDATA_HALT_ACKNOWLEDGE          (KDATA_BASE_ADDR + 0x003A)
-
-#define KDATA_ADC1_XFER0                (KDATA_BASE_ADDR + 0x003B)
-#define KDATA_ADC1_XFER_ENDMARK         (KDATA_BASE_ADDR + 0x003C)
-#define KDATA_ADC1_LEFT_VOLUME			(KDATA_BASE_ADDR + 0x003D)
-#define KDATA_ADC1_RIGHT_VOLUME  		(KDATA_BASE_ADDR + 0x003E)
-#define KDATA_ADC1_LEFT_SUR_VOL			(KDATA_BASE_ADDR + 0x003F)
-#define KDATA_ADC1_RIGHT_SUR_VOL		(KDATA_BASE_ADDR + 0x0040)
-
-#define KDATA_ADC2_XFER0                (KDATA_BASE_ADDR + 0x0041)
-#define KDATA_ADC2_XFER_ENDMARK         (KDATA_BASE_ADDR + 0x0042)
-#define KDATA_ADC2_LEFT_VOLUME			(KDATA_BASE_ADDR + 0x0043)
-#define KDATA_ADC2_RIGHT_VOLUME			(KDATA_BASE_ADDR + 0x0044)
-#define KDATA_ADC2_LEFT_SUR_VOL			(KDATA_BASE_ADDR + 0x0045)
-#define KDATA_ADC2_RIGHT_SUR_VOL		(KDATA_BASE_ADDR + 0x0046)
-
-#define KDATA_CD_XFER0					(KDATA_BASE_ADDR + 0x0047)					
-#define KDATA_CD_XFER_ENDMARK			(KDATA_BASE_ADDR + 0x0048)
-#define KDATA_CD_LEFT_VOLUME			(KDATA_BASE_ADDR + 0x0049)
-#define KDATA_CD_RIGHT_VOLUME			(KDATA_BASE_ADDR + 0x004A)
-#define KDATA_CD_LEFT_SUR_VOL			(KDATA_BASE_ADDR + 0x004B)
-#define KDATA_CD_RIGHT_SUR_VOL			(KDATA_BASE_ADDR + 0x004C)
-
-#define KDATA_MIC_XFER0					(KDATA_BASE_ADDR + 0x004D)
-#define KDATA_MIC_XFER_ENDMARK			(KDATA_BASE_ADDR + 0x004E)
-#define KDATA_MIC_VOLUME				(KDATA_BASE_ADDR + 0x004F)
-#define KDATA_MIC_SUR_VOL				(KDATA_BASE_ADDR + 0x0050)
-
-#define KDATA_I2S_XFER0                 (KDATA_BASE_ADDR + 0x0051)
-#define KDATA_I2S_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0052)
-
-#define KDATA_CHI_XFER0                 (KDATA_BASE_ADDR + 0x0053)
-#define KDATA_CHI_XFER_ENDMARK          (KDATA_BASE_ADDR + 0x0054)
-
-#define KDATA_SPDIF_XFER                (KDATA_BASE_ADDR + 0x0055)
-#define KDATA_SPDIF_CURRENT_FRAME       (KDATA_BASE_ADDR + 0x0056)
-#define KDATA_SPDIF_FRAME0              (KDATA_BASE_ADDR + 0x0057)
-#define KDATA_SPDIF_FRAME1              (KDATA_BASE_ADDR + 0x0058)
-#define KDATA_SPDIF_FRAME2              (KDATA_BASE_ADDR + 0x0059)
-
-#define KDATA_SPDIF_REQUEST             (KDATA_BASE_ADDR + 0x005A)
-#define KDATA_SPDIF_TEMP                (KDATA_BASE_ADDR + 0x005B)
-
-#define KDATA_SPDIFIN_XFER0             (KDATA_BASE_ADDR + 0x005C)
-#define KDATA_SPDIFIN_XFER_ENDMARK      (KDATA_BASE_ADDR + 0x005D)
-#define KDATA_SPDIFIN_INT_METER         (KDATA_BASE_ADDR + 0x005E)
-
-#define KDATA_DSP_RESET_COUNT           (KDATA_BASE_ADDR + 0x005F)
-#define KDATA_DEBUG_OUTPUT              (KDATA_BASE_ADDR + 0x0060)
-
-#define KDATA_KERNEL_ISR_LIST           (KDATA_BASE_ADDR + 0x0061)
-
-#define KDATA_KERNEL_ISR_CBSR1          (KDATA_BASE_ADDR + 0x0062)
-#define KDATA_KERNEL_ISR_CBER1          (KDATA_BASE_ADDR + 0x0063)
-#define KDATA_KERNEL_ISR_CBCR           (KDATA_BASE_ADDR + 0x0064)
-#define KDATA_KERNEL_ISR_AR0            (KDATA_BASE_ADDR + 0x0065)
-#define KDATA_KERNEL_ISR_AR1            (KDATA_BASE_ADDR + 0x0066)
-#define KDATA_KERNEL_ISR_AR2            (KDATA_BASE_ADDR + 0x0067)
-#define KDATA_KERNEL_ISR_AR3            (KDATA_BASE_ADDR + 0x0068)
-#define KDATA_KERNEL_ISR_AR4            (KDATA_BASE_ADDR + 0x0069)
-#define KDATA_KERNEL_ISR_AR5            (KDATA_BASE_ADDR + 0x006A)
-#define KDATA_KERNEL_ISR_BRCR           (KDATA_BASE_ADDR + 0x006B)
-#define KDATA_KERNEL_ISR_PASR           (KDATA_BASE_ADDR + 0x006C)
-#define KDATA_KERNEL_ISR_PAER           (KDATA_BASE_ADDR + 0x006D)
-
-#define KDATA_CLIENT_SCRATCH0           (KDATA_BASE_ADDR + 0x006E)
-#define KDATA_CLIENT_SCRATCH1           (KDATA_BASE_ADDR + 0x006F)
-#define KDATA_KERNEL_SCRATCH            (KDATA_BASE_ADDR + 0x0070)
-#define KDATA_KERNEL_ISR_SCRATCH        (KDATA_BASE_ADDR + 0x0071)
-
-#define KDATA_OUEUE_LEFT                (KDATA_BASE_ADDR + 0x0072)
-#define KDATA_QUEUE_RIGHT               (KDATA_BASE_ADDR + 0x0073)
-
-#define KDATA_ADC1_REQUEST              (KDATA_BASE_ADDR + 0x0074)
-#define KDATA_ADC2_REQUEST              (KDATA_BASE_ADDR + 0x0075)
-#define KDATA_CD_REQUEST				(KDATA_BASE_ADDR + 0x0076)
-#define KDATA_MIC_REQUEST				(KDATA_BASE_ADDR + 0x0077)
-
-#define KDATA_ADC1_MIXER_REQUEST        (KDATA_BASE_ADDR + 0x0078)
-#define KDATA_ADC2_MIXER_REQUEST        (KDATA_BASE_ADDR + 0x0079)
-#define KDATA_CD_MIXER_REQUEST			(KDATA_BASE_ADDR + 0x007A)
-#define KDATA_MIC_MIXER_REQUEST			(KDATA_BASE_ADDR + 0x007B)
-#define KDATA_MIC_SYNC_COUNTER			(KDATA_BASE_ADDR + 0x007C)
-
-/*
- * second 'segment' (?) reserved for mixer
- * buffers..
- */
-
-#define KDATA_MIXER_WORD0               (KDATA_BASE_ADDR2 + 0x0000)
-#define KDATA_MIXER_WORD1               (KDATA_BASE_ADDR2 + 0x0001)
-#define KDATA_MIXER_WORD2               (KDATA_BASE_ADDR2 + 0x0002)
-#define KDATA_MIXER_WORD3               (KDATA_BASE_ADDR2 + 0x0003)
-#define KDATA_MIXER_WORD4               (KDATA_BASE_ADDR2 + 0x0004)
-#define KDATA_MIXER_WORD5               (KDATA_BASE_ADDR2 + 0x0005)
-#define KDATA_MIXER_WORD6               (KDATA_BASE_ADDR2 + 0x0006)
-#define KDATA_MIXER_WORD7               (KDATA_BASE_ADDR2 + 0x0007)
-#define KDATA_MIXER_WORD8               (KDATA_BASE_ADDR2 + 0x0008)
-#define KDATA_MIXER_WORD9               (KDATA_BASE_ADDR2 + 0x0009)
-#define KDATA_MIXER_WORDA               (KDATA_BASE_ADDR2 + 0x000A)
-#define KDATA_MIXER_WORDB               (KDATA_BASE_ADDR2 + 0x000B)
-#define KDATA_MIXER_WORDC               (KDATA_BASE_ADDR2 + 0x000C)
-#define KDATA_MIXER_WORDD               (KDATA_BASE_ADDR2 + 0x000D)
-#define KDATA_MIXER_WORDE               (KDATA_BASE_ADDR2 + 0x000E)
-#define KDATA_MIXER_WORDF               (KDATA_BASE_ADDR2 + 0x000F)
-
-#define KDATA_MIXER_XFER0               (KDATA_BASE_ADDR2 + 0x0010)
-#define KDATA_MIXER_XFER1               (KDATA_BASE_ADDR2 + 0x0011)
-#define KDATA_MIXER_XFER2               (KDATA_BASE_ADDR2 + 0x0012)
-#define KDATA_MIXER_XFER3               (KDATA_BASE_ADDR2 + 0x0013)
-#define KDATA_MIXER_XFER4               (KDATA_BASE_ADDR2 + 0x0014)
-#define KDATA_MIXER_XFER5               (KDATA_BASE_ADDR2 + 0x0015)
-#define KDATA_MIXER_XFER6               (KDATA_BASE_ADDR2 + 0x0016)
-#define KDATA_MIXER_XFER7               (KDATA_BASE_ADDR2 + 0x0017)
-#define KDATA_MIXER_XFER8               (KDATA_BASE_ADDR2 + 0x0018)
-#define KDATA_MIXER_XFER9               (KDATA_BASE_ADDR2 + 0x0019)
-#define KDATA_MIXER_XFER_ENDMARK        (KDATA_BASE_ADDR2 + 0x001A)
-
-#define KDATA_MIXER_TASK_NUMBER         (KDATA_BASE_ADDR2 + 0x001B)
-#define KDATA_CURRENT_MIXER             (KDATA_BASE_ADDR2 + 0x001C)
-#define KDATA_MIXER_ACTIVE              (KDATA_BASE_ADDR2 + 0x001D)
-#define KDATA_MIXER_BANK_STATUS         (KDATA_BASE_ADDR2 + 0x001E)
-#define KDATA_DAC_LEFT_VOLUME	        (KDATA_BASE_ADDR2 + 0x001F)
-#define KDATA_DAC_RIGHT_VOLUME          (KDATA_BASE_ADDR2 + 0x0020)
-
-#define MAX_INSTANCE_MINISRC            (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
-#define MAX_VIRTUAL_DMA_CHANNELS        (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
-#define MAX_VIRTUAL_MIXER_CHANNELS      (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
-#define MAX_VIRTUAL_ADC1_CHANNELS       (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
-
-/*
- * client data area offsets
- */
-#define CDATA_INSTANCE_READY            0x00
-
-#define CDATA_HOST_SRC_ADDRL            0x01
-#define CDATA_HOST_SRC_ADDRH            0x02
-#define CDATA_HOST_SRC_END_PLUS_1L      0x03
-#define CDATA_HOST_SRC_END_PLUS_1H      0x04
-#define CDATA_HOST_SRC_CURRENTL         0x05
-#define CDATA_HOST_SRC_CURRENTH         0x06
-
-#define CDATA_IN_BUF_CONNECT            0x07
-#define CDATA_OUT_BUF_CONNECT           0x08
-
-#define CDATA_IN_BUF_BEGIN              0x09
-#define CDATA_IN_BUF_END_PLUS_1         0x0A
-#define CDATA_IN_BUF_HEAD               0x0B
-#define CDATA_IN_BUF_TAIL               0x0C
-#define CDATA_OUT_BUF_BEGIN             0x0D
-#define CDATA_OUT_BUF_END_PLUS_1        0x0E
-#define CDATA_OUT_BUF_HEAD              0x0F
-#define CDATA_OUT_BUF_TAIL              0x10
-
-#define CDATA_DMA_CONTROL               0x11
-#define CDATA_RESERVED                  0x12
-
-#define CDATA_FREQUENCY                 0x13
-#define CDATA_LEFT_VOLUME               0x14
-#define CDATA_RIGHT_VOLUME              0x15
-#define CDATA_LEFT_SUR_VOL              0x16
-#define CDATA_RIGHT_SUR_VOL             0x17
-
-#define CDATA_HEADER_LEN                0x18
-
-#define SRC3_DIRECTION_OFFSET           CDATA_HEADER_LEN
-#define SRC3_MODE_OFFSET                (CDATA_HEADER_LEN + 1)
-#define SRC3_WORD_LENGTH_OFFSET         (CDATA_HEADER_LEN + 2)
-#define SRC3_PARAMETER_OFFSET           (CDATA_HEADER_LEN + 3)
-#define SRC3_COEFF_ADDR_OFFSET          (CDATA_HEADER_LEN + 8)
-#define SRC3_FILTAP_ADDR_OFFSET         (CDATA_HEADER_LEN + 10)
-#define SRC3_TEMP_INBUF_ADDR_OFFSET     (CDATA_HEADER_LEN + 16)
-#define SRC3_TEMP_OUTBUF_ADDR_OFFSET    (CDATA_HEADER_LEN + 17)
-
-#define MINISRC_IN_BUFFER_SIZE   ( 0x50 * 2 )
-#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
-#define MINISRC_OUT_BUFFER_SIZE  ( 0x50 * 2 * 2)
-#define MINISRC_TMP_BUFFER_SIZE  ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
-#define MINISRC_BIQUAD_STAGE    2
-#define MINISRC_COEF_LOC          0X175
-
-#define DMACONTROL_BLOCK_MASK           0x000F
-#define  DMAC_BLOCK0_SELECTOR           0x0000
-#define  DMAC_BLOCK1_SELECTOR           0x0001
-#define  DMAC_BLOCK2_SELECTOR           0x0002
-#define  DMAC_BLOCK3_SELECTOR           0x0003
-#define  DMAC_BLOCK4_SELECTOR           0x0004
-#define  DMAC_BLOCK5_SELECTOR           0x0005
-#define  DMAC_BLOCK6_SELECTOR           0x0006
-#define  DMAC_BLOCK7_SELECTOR           0x0007
-#define  DMAC_BLOCK8_SELECTOR           0x0008
-#define  DMAC_BLOCK9_SELECTOR           0x0009
-#define  DMAC_BLOCKA_SELECTOR           0x000A
-#define  DMAC_BLOCKB_SELECTOR           0x000B
-#define  DMAC_BLOCKC_SELECTOR           0x000C
-#define  DMAC_BLOCKD_SELECTOR           0x000D
-#define  DMAC_BLOCKE_SELECTOR           0x000E
-#define  DMAC_BLOCKF_SELECTOR           0x000F
-#define DMACONTROL_PAGE_MASK            0x00F0
-#define  DMAC_PAGE0_SELECTOR            0x0030
-#define  DMAC_PAGE1_SELECTOR            0x0020
-#define  DMAC_PAGE2_SELECTOR            0x0010
-#define  DMAC_PAGE3_SELECTOR            0x0000
-#define DMACONTROL_AUTOREPEAT           0x1000
-#define DMACONTROL_STOPPED              0x2000
-#define DMACONTROL_DIRECTION            0x0100
-
-
-/*
- * DSP Code images
- */
-
-static u16 assp_kernel_image[] = {
-    0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4, 
-    0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 
-    0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 
-    0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4, 
-    0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08, 
-    0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909, 
-    0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41, 
-    0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308, 
-    0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910, 
-    0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00, 
-    0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026, 
-    0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0, 
-    0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012, 
-    0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A, 
-    0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000, 
-    0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05, 
-    0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26, 
-    0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300, 
-    0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88, 
-    0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008, 
-    0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80, 
-    0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71, 
-    0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A, 
-    0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100, 
-    0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900, 
-    0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903, 
-    0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309, 
-    0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B, 
-    0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540, 
-    0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C, 
-    0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380, 
-    0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340, 
-    0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041, 
-    0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18, 
-    0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 
-    0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9, 
-    0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8, 
-    0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A, 
-    0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80, 
-    0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 
-    0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80, 
-    0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A, 
-    0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F, 
-    0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1, 
-    0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034, 
-    0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 
-    0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977, 
-    0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B, 
-    0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388, 
-    0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 
-    0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473, 
-    0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473, 
-    0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880, 
-    0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80, 
-    0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6, 
-    0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909, 
-    0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED, 
-    0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005, 
-    0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 
-    0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4, 
-    0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 
-    0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10, 
-    0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070, 
-    0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71, 
-    0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A, 
-    0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061, 
-    0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A, 
-    0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6, 
-    0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A, 
-    0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6, 
-    0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358, 
-    0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6, 
-    0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9, 
-    0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379, 
-    0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6, 
-    0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C, 
-    0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166, 
-    0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B, 
-    0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A, 
-    0xBE3A, 
-};
-
-/*
- * Mini sample rate converter code image
- * that is to be loaded at 0x400 on the DSP.
- */
-static u16 assp_minisrc_image[] = {
-
-    0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412, 
-    0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41, 
-    0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907, 
-    0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01, 
-    0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904, 
-    0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D, 
-    0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD, 
-    0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22, 
-    0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0, 
-    0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9, 
-    0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89, 
-    0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0, 
-    0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484, 
-    0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80, 
-    0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624, 
-    0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4, 
-    0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027, 
-    0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903, 
-    0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809, 
-    0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46, 
-    0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47, 
-    0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0, 
-    0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516, 
-    0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E, 
-    0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C, 
-    0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180, 
-    0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E, 
-    0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0, 
-    0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0, 
-    0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0, 
-    0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F, 
-    0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
-    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 
-};
-
diff --git a/sound/oss/maui.c b/sound/oss/maui.c
deleted file mode 100644
index 317f225..0000000
--- a/sound/oss/maui.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * sound/oss/maui.c
- *
- * The low level driver for Turtle Beach Maui and Tropez.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *	Changes:
- *		Alan Cox		General clean up, use kernel IRQ 
- *					system
- *		Christoph Hellwig	Adapted to module_init/module_exit
- *		Bartlomiej Zolnierkiewicz
- *					Added __init to download_code()
- *
- *	Status:
- *		Andrew J. Kroll		Tested 06/01/1999 with:
- *					* OSWF.MOT File Version: 1.15
- *					* OSWF.MOT File Dated: 09/12/94
- *					* Older versions will cause problems.
- */
-
-#include <linux/interrupt.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#define USE_SEQ_MACROS
-#define USE_SIMPLE_MACROS
-
-#include "sound_config.h"
-#include "sound_firmware.h"
-
-#include "mpu401.h"
-
-static int      maui_base = 0x330;
-
-static volatile int irq_ok;
-static int     *maui_osp;
-
-#define HOST_DATA_PORT	(maui_base + 2)
-#define HOST_STAT_PORT	(maui_base + 3)
-#define HOST_CTRL_PORT	(maui_base + 3)
-
-#define STAT_TX_INTR	0x40
-#define STAT_TX_AVAIL	0x20
-#define STAT_TX_IENA	0x10
-#define STAT_RX_INTR	0x04
-#define STAT_RX_AVAIL	0x02
-#define STAT_RX_IENA	0x01
-
-static int      (*orig_load_patch)(int dev, int format, const char __user *addr,
-			      int offs, int count, int pmgr_flag) = NULL;
-
-#include "maui_boot.h"
-
-static int maui_wait(int mask)
-{
-	int i;
-
-	/*
-	 * Perform a short initial wait without sleeping
-	 */
-
-	for (i = 0; i < 100; i++)
-		if (inb(HOST_STAT_PORT) & mask)
-			return 1;
-
-	/*
-	 * Wait up to 15 seconds with sleeping
-	 */
-
-	for (i = 0; i < 150; i++) {
-		if (inb(HOST_STAT_PORT) & mask)
-			return 1;
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ / 10);
-		if (signal_pending(current))
-			return 0;
-	}
-	return 0;
-}
-
-static int maui_read(void)
-{
-	if (maui_wait(STAT_RX_AVAIL))
-		return inb(HOST_DATA_PORT);
-	return -1;
-}
-
-static int maui_write(unsigned char data)
-{
-	if (maui_wait(STAT_TX_AVAIL)) {
-		outb((data), HOST_DATA_PORT);
-		return 1;
-	}
-	printk(KERN_WARNING "Maui: Write timeout\n");
-	return 0;
-}
-
-static irqreturn_t mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
-	irq_ok = 1;
-	return IRQ_HANDLED;
-}
-
-static int __init download_code(void)
-{
-	int i, lines = 0;
-	int eol_seen = 0, done = 0;
-	int skip = 1;
-
-	printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
-
-	for (i = 0; i < maui_osLen; i++) {
-		if (maui_os[i] != '\r') {
-			if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) {
-				skip = 0;
-
-				if (maui_os[i] == '\n')
-					eol_seen = skip = 1;
-				else if (maui_os[i] == 'S') {
-					if (maui_os[i + 1] == '8')
-						done = 1;
-					if (!maui_write(0xF1))
-						goto failure;
-					if (!maui_write('S'))
-						goto failure;
-				} else {
-					if (!maui_write(maui_os[i]))
-						goto failure;
-				}
-
-				if (eol_seen) {
-					int c = 0;
-					int n;
-
-					eol_seen = 0;
-
-					for (n = 0; n < 2; n++) {
-						if (maui_wait(STAT_RX_AVAIL)) {
-							c = inb(HOST_DATA_PORT);
-							break;
-						}
-					}
-					if (c != 0x80) {
-						printk("Download not acknowledged\n");
-						return 0;
-					}
-					else if (!(lines++ % 10))
-						printk(".");
-
-					if (done) {
-						printk("\n");
-						printk(KERN_INFO "Download complete\n");
-						return 1;
-					}
-				}
-			}
-		}
-	}
-
-failure:
-	printk("\n");
-	printk(KERN_ERR "Download failed!!!\n");
-	return 0;
-}
-
-static int __init maui_init(int irq)
-{
-	unsigned char bits;
-
-	switch (irq) {
-		case 9:
-			bits = 0x00;
-			break;
-		case 5:
-			bits = 0x08;
-			break;
-		case 12:
-			bits = 0x10;
-			break;
-		case 15:
-			bits = 0x18;
-			break;
-
-		default:
-			printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq);
-			return 0;
-	}
-	outb((0x00), HOST_CTRL_PORT);	/* Reset */
-	outb((bits), HOST_DATA_PORT);	/* Set the IRQ bits */
-	outb((bits | 0x80), HOST_DATA_PORT);	/* Set the IRQ bits again? */
-	outb((0x80), HOST_CTRL_PORT);	/* Leave reset */
-	outb((0x80), HOST_CTRL_PORT);	/* Leave reset */
-	outb((0xD0), HOST_CTRL_PORT);	/* Cause interrupt */
-
-#ifdef CONFIG_SMP
-	{
-		int i;
-		for (i = 0; i < 1000000 && !irq_ok; i++)
-			;
-		if (!irq_ok)
-			return 0;
-	}
-#endif
-	outb((0x80), HOST_CTRL_PORT);	/* Leave reset */
-
-	printk(KERN_INFO "Turtle Beach Maui initialization\n");
-
-	if (!download_code())
-		return 0;
-
-	outb((0xE0), HOST_CTRL_PORT);	/* Normal operation */
-
-	/* Select mpu401 mode */
-
-	maui_write(0xf0);
-	maui_write(1);
-	if (maui_read() != 0x80) {
-		maui_write(0xf0);
-		maui_write(1);
-		if (maui_read() != 0x80)
-			printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n");
-	}
-	printk(KERN_INFO "Maui initialized OK\n");
-	return 1;
-}
-
-static int maui_short_wait(int mask) {
-	int i;
-
-	for (i = 0; i < 1000; i++) {
-		if (inb(HOST_STAT_PORT) & mask) {
-			return 1;
-		}
-	}
-	return 0;
-}
-
-static int maui_load_patch(int dev, int format, const char __user *addr,
-		int offs, int count, int pmgr_flag)
-{
-
-	struct sysex_info header;
-	unsigned long left, src_offs;
-	int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
-	int i;
-
-	if (format == SYSEX_PATCH)	/* Handled by midi_synth.c */
-		return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
-
-	if (format != MAUI_PATCH)
-	{
-		  printk(KERN_WARNING "Maui: Unknown patch format\n");
-	}
-	if (count < hdr_size) {
-/*		  printk("Maui error: Patch header too short\n");*/
-		  return -EINVAL;
-	}
-	count -= hdr_size;
-
-	/*
-	 * Copy the header from user space but ignore the first bytes which have
-	 * been transferred already.
-	 */
-
-	if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
-		return -EFAULT;
-
-	if (count < header.len) {
-		  printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len);
-		  header.len = count;
-	}
-	left = header.len;
-	src_offs = 0;
-
-	for (i = 0; i < left; i++) {
-		unsigned char   data;
-
-		if(get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i])))
-			return -EFAULT;
-		if (i == 0 && !(data & 0x80))
-			return -EINVAL;
-
-		if (maui_write(data) == -1)
-			return -EIO;
-	}
-
-	if ((i = maui_read()) != 0x80) {
-		if (i != -1)
-			printk("Maui: Error status %02x\n", i);
-		return -EIO;
-	}
-	return 0;
-}
-
-static int __init probe_maui(struct address_info *hw_config)
-{
-	struct resource *ports;
-	int this_dev;
-	int i;
-	int tmp1, tmp2, ret;
-
-	ports = request_region(hw_config->io_base, 2, "mpu401");
-	if (!ports)
-		return 0;
-
-	if (!request_region(hw_config->io_base + 2, 6, "Maui"))
-		goto out;
-
-	maui_base = hw_config->io_base;
-	maui_osp = hw_config->osp;
-
-	if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
-		goto out2;
-
-	/*
-	 * Initialize the processor if necessary
-	 */
-
-	if (maui_osLen > 0) {
-		if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
-			!maui_write(0x9F) ||	/* Report firmware version */
-			!maui_short_wait(STAT_RX_AVAIL) ||
-			maui_read() == -1 || maui_read() == -1)
-			if (!maui_init(hw_config->irq))
-				goto out3;
-	}
-	if (!maui_write(0xCF))	/* Report hardware version */ {
-		printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
-		goto out3;
-	}
-	if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
-		printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
-		goto out3;
-	}
-	if (tmp1 == 0xff || tmp2 == 0xff)
-		goto out3;
-	printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
-
-	if (!maui_write(0x9F))	/* Report firmware version */
-		goto out3;
-	if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
-		goto out3;
-
-	printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
-
-	if (!maui_write(0x85))	/* Report free DRAM */
-		goto out3;
-	tmp1 = 0;
-	for (i = 0; i < 4; i++) {
-		tmp1 |= maui_read() << (7 * i);
-	}
-	printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
-
-	for (i = 0; i < 1000; i++)
-		if (probe_mpu401(hw_config, ports))
-			break;
-
-	ret = probe_mpu401(hw_config, ports);
-	if (!ret)
-		goto out3;
-
-	conf_printf("Maui", hw_config);
-
-	hw_config->irq *= -1;
-	hw_config->name = "Maui";
-	attach_mpu401(hw_config, THIS_MODULE);
-
-	if (hw_config->slots[1] != -1)	/* The MPU401 driver installed itself */ {
-		struct synth_operations *synth;
-
-		this_dev = hw_config->slots[1];
-
-		/*
-		 * Intercept patch loading calls so that they can be handled
-		 * by the Maui driver.
-		 */
-
-		synth = midi_devs[this_dev]->converter;
-		if (synth != NULL) {
-			synth->id = "MAUI";
-			orig_load_patch = synth->load_patch;
-			synth->load_patch = &maui_load_patch;
-		} else
-			printk(KERN_ERR "Maui: Can't install patch loader\n");
-	}
-	return 1;
-
-out3:
-	free_irq(hw_config->irq, NULL);
-out2:
-	release_region(hw_config->io_base + 2, 6);
-out:
-	release_region(hw_config->io_base, 2);
-	return 0;
-}
-
-static void __exit unload_maui(struct address_info *hw_config)
-{
-	int irq = hw_config->irq;
-	release_region(hw_config->io_base + 2, 6);
-	unload_mpu401(hw_config);
-
-	if (irq < 0)
-		irq = -irq;
-	if (irq > 0)
-		free_irq(irq, NULL);
-}
-
-static int fw_load;
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-
-/*
- *	Install a Maui card. Needs mpu401 loaded already.
- */
-
-static int __init init_maui(void)
-{
-	printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n");
-
-	cfg.io_base = io;
-	cfg.irq = irq;
-
-	if (cfg.io_base == -1 || cfg.irq == -1) {
-		printk(KERN_INFO "maui: irq and io must be set.\n");
-		return -EINVAL;
-	}
-
-	if (maui_os == NULL) {
-		fw_load = 1;
-		maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
-	}
-	if (probe_maui(&cfg) == 0)
-		return -ENODEV;
-
-	return 0;
-}
-
-static void __exit cleanup_maui(void)
-{
-	if (fw_load && maui_os)
-		vfree(maui_os);
-	unload_maui(&cfg);
-}
-
-module_init(init_maui);
-module_exit(cleanup_maui);
-
-#ifndef MODULE
-static int __init setup_maui(char *str)
-{
-        /* io, irq */
-	int ints[3];
-	
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	
-	io = ints[1];
-	irq = ints[2];
-
-	return 1;
-}
-
-__setup("maui=", setup_maui);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/midi_syms.c b/sound/oss/midi_syms.c
deleted file mode 100644
index 5b146dd..0000000
--- a/sound/oss/midi_syms.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Exported symbols for midi driver.
- */
-
-#include <linux/module.h>
-
-char midi_syms_symbol;
-
-#include "sound_config.h"
-#define _MIDI_SYNTH_C_
-#include "midi_synth.h"
-
-EXPORT_SYMBOL(do_midi_msg);
-EXPORT_SYMBOL(midi_synth_open);
-EXPORT_SYMBOL(midi_synth_close);
-EXPORT_SYMBOL(midi_synth_ioctl);
-EXPORT_SYMBOL(midi_synth_kill_note);
-EXPORT_SYMBOL(midi_synth_start_note);
-EXPORT_SYMBOL(midi_synth_set_instr);
-EXPORT_SYMBOL(midi_synth_reset);
-EXPORT_SYMBOL(midi_synth_hw_control);
-EXPORT_SYMBOL(midi_synth_aftertouch);
-EXPORT_SYMBOL(midi_synth_controller);
-EXPORT_SYMBOL(midi_synth_panning);
-EXPORT_SYMBOL(midi_synth_setup_voice);
-EXPORT_SYMBOL(midi_synth_send_sysex);
-EXPORT_SYMBOL(midi_synth_bender);
-EXPORT_SYMBOL(midi_synth_load_patch);
-EXPORT_SYMBOL(MIDIbuf_avail);
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c
index d2ab5c0..9e45098 100644
--- a/sound/oss/midi_synth.c
+++ b/sound/oss/midi_synth.c
@@ -84,6 +84,7 @@
 		  ;
 	  }
 }
+EXPORT_SYMBOL(do_midi_msg);
 
 static void
 midi_outc(int midi_dev, int data)
@@ -276,6 +277,7 @@
 		return -EINVAL;
 	}
 }
+EXPORT_SYMBOL(midi_synth_ioctl);
 
 int
 midi_synth_kill_note(int dev, int channel, int note, int velocity)
@@ -342,6 +344,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(midi_synth_kill_note);
 
 int
 midi_synth_set_instr(int dev, int channel, int instr_no)
@@ -364,6 +367,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(midi_synth_set_instr);
 
 int
 midi_synth_start_note(int dev, int channel, int note, int velocity)
@@ -405,6 +409,7 @@
 	  }
 	return 0;
 }
+EXPORT_SYMBOL(midi_synth_start_note);
 
 void
 midi_synth_reset(int dev)
@@ -412,6 +417,7 @@
 
 	leave_sysex(dev);
 }
+EXPORT_SYMBOL(midi_synth_reset);
 
 int
 midi_synth_open(int dev, int mode)
@@ -444,6 +450,7 @@
 
 	return 1;
 }
+EXPORT_SYMBOL(midi_synth_open);
 
 void
 midi_synth_close(int dev)
@@ -459,11 +466,13 @@
 
 	midi_devs[orig_dev]->close(orig_dev);
 }
+EXPORT_SYMBOL(midi_synth_close);
 
 void
 midi_synth_hw_control(int dev, unsigned char *event)
 {
 }
+EXPORT_SYMBOL(midi_synth_hw_control);
 
 int
 midi_synth_load_patch(int dev, int format, const char __user *addr,
@@ -542,11 +551,13 @@
 		midi_outc(orig_dev, 0xf7);
 	return 0;
 }
-  
+EXPORT_SYMBOL(midi_synth_load_patch);
+
 void midi_synth_panning(int dev, int channel, int pressure)
 {
 }
-  
+EXPORT_SYMBOL(midi_synth_panning);
+
 void midi_synth_aftertouch(int dev, int channel, int pressure)
 {
 	int             orig_dev = synth_devs[dev]->midi_dev;
@@ -576,6 +587,7 @@
 
 	midi_outc(orig_dev, pressure);
 }
+EXPORT_SYMBOL(midi_synth_aftertouch);
 
 void
 midi_synth_controller(int dev, int channel, int ctrl_num, int value)
@@ -604,6 +616,7 @@
 	midi_outc(orig_dev, ctrl_num);
 	midi_outc(orig_dev, value & 0x7f);
 }
+EXPORT_SYMBOL(midi_synth_controller);
 
 void
 midi_synth_bender(int dev, int channel, int value)
@@ -635,11 +648,13 @@
 	midi_outc(orig_dev, value & 0x7f);
 	midi_outc(orig_dev, (value >> 7) & 0x7f);
 }
+EXPORT_SYMBOL(midi_synth_bender);
 
 void
 midi_synth_setup_voice(int dev, int voice, int channel)
 {
 }
+EXPORT_SYMBOL(midi_synth_setup_voice);
 
 int
 midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
@@ -695,3 +710,5 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(midi_synth_send_sysex);
+
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
index c0e4bbc..a40be0c 100644
--- a/sound/oss/midibuf.c
+++ b/sound/oss/midibuf.c
@@ -414,18 +414,11 @@
 }
 
 
-void MIDIbuf_init(void)
-{
-	/* drag in midi_syms.o */
-	{
-		extern char midi_syms_symbol;
-		midi_syms_symbol = 0;
-	}
-}
-
 int MIDIbuf_avail(int dev)
 {
 	if (midi_in_buf[dev])
 		return DATA_AVAIL (midi_in_buf[dev]);
 	return 0;
 }
+EXPORT_SYMBOL(MIDIbuf_avail);
+
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index 321f4c4..162d07c 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -432,16 +432,7 @@
 	devc->m_busy = 0;
 }
 
-int intchk_mpu401(void *dev_id)
-{
-	struct mpu_config *devc;
-	int dev = (int) dev_id;
-
-	devc = &dev_conf[dev];
-	return input_avail(devc);
-}
-
-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
 {
 	struct mpu_config *devc;
 	int dev = (int) dev_id;
@@ -1761,8 +1752,6 @@
 EXPORT_SYMBOL(probe_mpu401);
 EXPORT_SYMBOL(attach_mpu401);
 EXPORT_SYMBOL(unload_mpu401);
-EXPORT_SYMBOL(intchk_mpu401);
-EXPORT_SYMBOL(mpuintr);
 
 static struct address_info cfg;
 
diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h
index bdc5bde..84c0e95 100644
--- a/sound/oss/mpu401.h
+++ b/sound/oss/mpu401.h
@@ -10,5 +10,3 @@
 int attach_mpu401(struct address_info * hw_config, struct module *owner);
 void unload_mpu401(struct address_info *hw_info);
 
-int intchk_mpu401(void *dev_id);
-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs * dummy);
diff --git a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c
deleted file mode 100644
index 2535ed0..0000000
--- a/sound/oss/opl3sa.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * sound/oss/opl3sa.c
- *
- * Low level driver for Yamaha YMF701B aka OPL3-SA chip
- * 
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- *	Alan Cox		Modularisation
- *	Christoph Hellwig	Adapted to module_init/module_exit
- *	Arnaldo C. de Melo	got rid of attach_uart401
- *
- * FIXME:
- * 	Check for install of mpu etc is wrong, should check result of the mss stuff
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-
-#undef  SB_OK
-
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#ifdef SB_OK
-#include "sb.h"
-static int sb_initialized;
-#endif
-
-static DEFINE_SPINLOCK(lock);
-
-static unsigned char opl3sa_read(int addr)
-{
-	unsigned long flags;
-	unsigned char tmp;
-
-	spin_lock_irqsave(&lock,flags);
-	outb((0x1d), 0xf86);	/* password */
-	outb(((unsigned char) addr), 0xf86);	/* address */
-	tmp = inb(0xf87);	/* data */
-	spin_unlock_irqrestore(&lock,flags);
-
-	return tmp;
-}
-
-static void opl3sa_write(int addr, int data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&lock,flags);
-	outb((0x1d), 0xf86);	/* password */
-	outb(((unsigned char) addr), 0xf86);	/* address */
-	outb(((unsigned char) data), 0xf87);	/* data */
-	spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init opl3sa_detect(void)
-{
-	int tmp;
-
-	if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04)
-	{
-		DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01)));
-		/* return 0; */
-	}
-
-	/*
-	 * Check that the password feature has any effect
-	 */
-	
-	if (inb(0xf87) == tmp)
-	{
-		DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87)));
-		return 0;
-	}
-	tmp = (opl3sa_read(0x04) & 0xe0) >> 5;
-
-	if (tmp != 0 && tmp != 1)
-	{
-		DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp));
-		return 0;
-	}
-	DDB(printk("OPL3-SA mode %x detected\n", tmp));
-
-	opl3sa_write(0x01, 0x00);	/* Disable MSS */
-	opl3sa_write(0x02, 0x00);	/* Disable SB */
-	opl3sa_write(0x03, 0x00);	/* Disable MPU */
-
-	return 1;
-}
-
-/*
- *    Probe and attach routines for the Windows Sound System mode of
- *     OPL3-SA
- */
-
-static int __init probe_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
-{
-	unsigned char tmp = 0x24;	/* WSS enable */
-
-	/*
-	 * Check if the IO port returns valid signature. The original MS Sound
-	 * system returns 0x04 while some cards (OPL3-SA for example)
-	 * return 0x00.
-	 */
-
-	if (!opl3sa_detect())
-	{
-		printk(KERN_ERR "OSS: OPL3-SA chip not found\n");
-		return 0;
-	}
-	
-	switch (hw_config->io_base)
-	{
-		case 0x530:
-			tmp |= 0x00;
-			break;
-		case 0xe80:
-			tmp |= 0x08;
-			break;
-		case 0xf40:
-			tmp |= 0x10;
-			break;
-		case 0x604:
-			tmp |= 0x18;
-			break;
-		default:
-			printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base);
-		  return 0;
-	}
-
-	opl3sa_write(0x01, tmp);	/* WSS setup register */
-
-	return probe_ms_sound(hw_config, ports);
-}
-
-static void __init attach_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
-{
-	int nm = num_mixers;
-
-	/* FIXME */
-	attach_ms_sound(hw_config, ports, THIS_MODULE);
-	if (num_mixers > nm)	/* A mixer was installed */
-	{
-		AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
-		AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
-		AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
-	}
-}
-
-
-static int __init probe_opl3sa_mpu(struct address_info *hw_config)
-{
-	unsigned char conf;
-	static signed char irq_bits[] = {
-		-1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
-	};
-
-	if (hw_config->irq > 10)
-	{
-		printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
-		return 0;
-	}
-	if (irq_bits[hw_config->irq] == -1)
-	{
-		printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
-		return 0;
-	}
-	switch (hw_config->io_base)
-	{
-		case 0x330:
-			conf = 0x00;
-			break;
-		case 0x332:
-			conf = 0x20;
-			break;
-		case 0x334:
-			conf = 0x40;
-			break;
-		case 0x300:
-			conf = 0x60;
-			break;
-		default:
-			return 0;	/* Invalid port */
-	}
-
-	conf |= 0x83;		/* MPU & OPL3 (synth) & game port enable */
-	conf |= irq_bits[hw_config->irq] << 2;
-
-	opl3sa_write(0x03, conf);
-
-	hw_config->name = "OPL3-SA (MPU401)";
-
-	return probe_uart401(hw_config, THIS_MODULE);
-}
-
-static void __exit unload_opl3sa_wss(struct address_info *hw_config)
-{
-	int dma2 = hw_config->dma2;
-
-	if (dma2 == -1)
-		dma2 = hw_config->dma;
-
-	release_region(0xf86, 2);
-	release_region(hw_config->io_base, 4);
-
-	ad1848_unload(hw_config->io_base + 4,
-		      hw_config->irq,
-		      hw_config->dma,
-		      dma2,
-		      0);
-	sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config)
-{
-	unload_uart401(hw_config);
-}
-
-#ifdef SB_OK
-static inline void __exit unload_opl3sa_sb(struct address_info *hw_config)
-{
-	sb_dsp_unload(hw_config);
-}
-#endif
-
-static int found_mpu;
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata io	= -1;
-static int __initdata irq	= -1;
-static int __initdata dma	= -1;
-static int __initdata dma2	= -1;
-static int __initdata mpu_io	= -1;
-static int __initdata mpu_irq	= -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma2, int, 0);
-module_param(mpu_io, int, 0);
-module_param(mpu_irq, int, 0);
-
-static int __init init_opl3sa(void)
-{
-	struct resource *ports;
-	if (io == -1 || irq == -1 || dma == -1) {
-		printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n");
-		return -EINVAL;
-	}
-
-	cfg.io_base = io;
-	cfg.irq = irq;
-	cfg.dma = dma;
-	cfg.dma2 = dma2;
-	
-	cfg_mpu.io_base = mpu_io;
-	cfg_mpu.irq = mpu_irq;
-
-	ports = request_region(io + 4, 4, "ad1848");
-	if (!ports)
-		return -EBUSY;
-
-	if (!request_region(0xf86, 2, "OPL3-SA"))/* Control port is busy */ {
-		release_region(io + 4, 4);
-		return 0;
-	}
-
-	if (!request_region(io, 4, "WSS config")) {
-		release_region(0x86, 2);
-		release_region(io + 4, 4);
-		return 0;
-	}
-
-	if (probe_opl3sa_wss(&cfg, ports) == 0) {
-		release_region(0xf86, 2);
-		release_region(io, 4);
-		release_region(io + 4, 4);
-		return -ENODEV;
-	}
-
-	found_mpu=probe_opl3sa_mpu(&cfg_mpu);
-
-	attach_opl3sa_wss(&cfg, ports);
-	return 0;
-}
-
-static void __exit cleanup_opl3sa(void)
-{
-	if(found_mpu)
-		unload_opl3sa_mpu(&cfg_mpu);
-	unload_opl3sa_wss(&cfg);
-}
-
-module_init(init_opl3sa);
-module_exit(cleanup_opl3sa);
-
-#ifndef MODULE
-static int __init setup_opl3sa(char *str)
-{
-	/* io, irq, dma, dma2, mpu_io, mpu_irq */
-	int ints[7];
-	
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	
-	io	= ints[1];
-	irq	= ints[2];
-	dma	= ints[3];
-	dma2	= ints[4];
-	mpu_io	= ints[5];
-	mpu_irq	= ints[6];
-
-	return 1;
-}
-
-__setup("opl3sa=", setup_opl3sa);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c
deleted file mode 100644
index f17d25b..0000000
--- a/sound/oss/rme96xx.c
+++ /dev/null
@@ -1,1857 +0,0 @@
-/* (C) 2000 Guenter Geiger <geiger@debian.org>
-   with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
-   based on es1370.c
-
-
-
-   *  10 Jan 2001: 0.1 initial version
-   *  19 Jan 2001: 0.2 fixed bug in select()
-   *  27 Apr 2001: 0.3 more than one card usable
-   *  11 May 2001: 0.4 fixed for SMP, included into kernel source tree
-   *  17 May 2001: 0.5 draining code didn't work on new cards
-   *  18 May 2001: 0.6 remove synchronize_irq() call 
-   *  17 Jul 2001: 0.7 updated xrmectrl to make it work for newer cards
-   *   2 feb 2002: 0.8 fixed pci device handling, see below for patches from Heiko (Thanks!)
-                       Marcus Meissner <Marcus.Meissner@caldera.de>
-
-		       Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-		       HP20020108 fixed handling of "large" read()
-		       HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
-		       HP20020118 made mixer ioctl and handling of devices>1 more safe
-		       HP20020201 fixed handling of "large" read() properly
-		       added REV 1.5 S/P-DIF receiver support
-		       SNDCTL_DSP_SPEED now returns the actual speed
-   *  10 Aug 2002: added synchronize_irq() again
-
-TODO:
-   - test more than one card --- done
-   - check for pci IOREGION (see es1370) in rme96xx_probe ??
-   - error detection
-   - mmap interface
-   - mixer mmap interface
-   - mixer ioctl
-   - get rid of noise upon first open (why ??)
-   - allow multiple open (at least for read)
-   - allow multiple open for non overlapping regions
-   - recheck the multiple devices part (offsets of different devices, etc)
-   - do decent draining in _release --- done
-   - SMP support
-   - what about using fragstotal>2 for small fragsize? (HP20020118)
-   - add support for AFMT_S32_LE
-*/
-
-#ifndef RMEVERSION
-#define RMEVERSION "0.8"
-#endif
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-#include <asm/dma.h>
-#include <asm/page.h>
-
-#include "rme96xx.h"
-
-#define NR_DEVICE 2
-
-static int devices = 1;
-module_param(devices, int, 0);
-MODULE_PARM_DESC(devices, "number of dsp devices allocated by the driver");
-
-
-MODULE_AUTHOR("Guenter Geiger, geiger@debian.org");
-MODULE_DESCRIPTION("RME9652/36 \"Hammerfall\" Driver");
-MODULE_LICENSE("GPL");
-
-
-#ifdef DEBUG
-#define DBG(x) printk("RME_DEBUG:");x
-#define COMM(x) printk("RME_COMM: " x "\n");
-#else
-#define DBG(x) while (0) {}
-#define COMM(x)
-#endif
-
-/*-------------------------------------------------------------------------- 
-                        Preporcessor Macros and Definitions
- --------------------------------------------------------------------------*/
-
-#define RME96xx_MAGIC 0x6473
-
-/* Registers-Space in offsets from base address with 16MByte size */
-
-#define RME96xx_IO_EXTENT     16l*1024l*1024l
-#define RME96xx_CHANNELS_PER_CARD 26
-
-/*                  Write - Register */
-
-/* 0,4,8,12,16,20,24,28 ... hardware init (erasing fifo-pointer intern) */
-#define RME96xx_num_of_init_regs   8
-
-#define RME96xx_init_buffer       (0/4)
-#define RME96xx_play_buffer       (32/4)  /* pointer to 26x64kBit RAM from mainboard */
-#define RME96xx_rec_buffer        (36/4)  /* pointer to 26x64kBit RAM from mainboard */
-#define RME96xx_control_register  (64/4)  /* exact meaning see below */
-#define RME96xx_irq_clear         (96/4)  /* irq acknowledge */
-#define RME96xx_time_code         (100/4) /* if used with alesis adat */
-#define RME96xx_thru_base         (128/4) /* 132...228 Thru for 26 channels */
-#define RME96xx_thru_channels     RME96xx_CHANNELS_PER_CARD
-
-/*                     Read Register */
-
-#define RME96xx_status_register    0     /* meaning see below */
-
-
-
-/* Status Register: */
-/* ------------------------------------------------------------------------ */
-#define RME96xx_IRQ          0x0000001 /* IRQ is High if not reset by RMExx_irq_clear */
-#define RME96xx_lock_2       0x0000002 /* ADAT 3-PLL: 1=locked, 0=unlocked */
-#define RME96xx_lock_1       0x0000004 /* ADAT 2-PLL: 1=locked, 0=unlocked */
-#define RME96xx_lock_0       0x0000008 /* ADAT 1-PLL: 1=locked, 0=unlocked */
-
-#define RME96xx_fs48         0x0000010 /* sample rate 0 ...44.1/88.2,  1 ... 48/96 Khz */
-#define RME96xx_wsel_rd      0x0000020 /* if Word-Clock is used and valid then 1 */
-#define RME96xx_buf_pos1     0x0000040 /* Bit 6..15 : Position of buffer-pointer in 64Bytes-blocks */
-#define RME96xx_buf_pos2     0x0000080 /* resolution +/- 1 64Byte/block (since 64Bytes bursts) */
- 
-#define RME96xx_buf_pos3     0x0000100 /* 10 bits = 1024 values */
-#define RME96xx_buf_pos4     0x0000200 /* if we mask off the first 6 bits, we can take the status */
-#define RME96xx_buf_pos5     0x0000400 /* register as sample counter in the hardware buffer */
-#define RME96xx_buf_pos6     0x0000800 
-
-#define RME96xx_buf_pos7     0x0001000 
-#define RME96xx_buf_pos8     0x0002000 
-#define RME96xx_buf_pos9     0x0004000
-#define RME96xx_buf_pos10    0x0008000 
-
-#define RME96xx_sync_2       0x0010000 /* if ADAT-IN3 synced to system clock */
-#define RME96xx_sync_1       0x0020000 /* if ADAT-IN2 synced to system clock */
-#define RME96xx_sync_0       0x0040000 /* if ADAT-IN1 synced to system clock */
-#define RME96xx_DS_rd        0x0080000 /* 1=Double Speed, 0=Normal Speed */
-
-#define RME96xx_tc_busy      0x0100000 /* 1=time-code copy in progress (960ms) */
-#define RME96xx_tc_out       0x0200000 /* time-code out bit */
-#define RME96xx_F_0          0x0400000 /*  000=64kHz, 100=88.2kHz, 011=96kHz  */
-#define RME96xx_F_1          0x0800000 /*  111=32kHz, 110=44.1kHz, 101=48kHz, */
-
-#define RME96xx_F_2          0x1000000 /*  001=Rev 1.5+ external Crystal Chip */
-#define RME96xx_ERF          0x2000000 /* Error-Flag of SDPIF Receiver (1=No Lock)*/
-#define RME96xx_buffer_id    0x4000000 /* toggles by each interrupt on rec/play */
-#define RME96xx_tc_valid     0x8000000 /* 1 = a signal is detected on time-code input */
-#define RME96xx_SPDIF_READ  0x10000000 /* byte available from Rev 1.5+ SPDIF interface */
-
-/* Status Register Fields */
-
-#define RME96xx_lock            (RME96xx_lock_0|RME96xx_lock_1|RME96xx_lock_2)
-#define RME96xx_sync            (RME96xx_sync_0|RME96xx_sync_1|RME96xx_sync_2)
-#define RME96xx_F               (RME96xx_F_0|RME96xx_F_1|RME96xx_F_2)
-#define rme96xx_decode_spdif_rate(x) ((x)>>22)
-
-/* Bit 6..15 : h/w buffer pointer */
-#define RME96xx_buf_pos          0x000FFC0 
-/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later
-   Rev G EEPROMS and Rev 1.5 cards or later.
-*/ 
-#define RME96xx_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME96xx_buf_pos))
-
-
-/* Control-Register: */			    
-/*--------------------------------------------------------------------------------*/
-
-#define RME96xx_start_bit	0x0001 /* start record/play */
-#define RME96xx_latency0	0x0002 /* Buffer size / latency */
-#define RME96xx_latency1	0x0004 /*   buffersize = 512Bytes * 2^n */
-#define RME96xx_latency2	0x0008 /*   0=64samples ... 7=8192samples */
-
-#define RME96xx_Master		0x0010 /* Clock Mode 1=Master, 0=Slave/Auto */
-#define RME96xx_IE		0x0020 /* Interupt Enable */
-#define RME96xx_freq		0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/
-#define RME96xx_freq1		0x0080 /* samplerate 0=32 kHz, 1=other rates ??? (from ALSA, but may be wrong) */
-#define RME96xx_DS              0x0100 /* double speed 0=44.1/48, 1=88.2/96 Khz */
-#define RME96xx_PRO		0x0200 /* SPDIF-OUT 0=consumer, 1=professional */
-#define RME96xx_EMP		0x0400 /* SPDIF-OUT emphasis 0=off, 1=on */
-#define RME96xx_Dolby		0x0800 /* SPDIF-OUT non-audio bit 1=set, 0=unset */
-
-#define RME96xx_opt_out	        0x1000 /* use 1st optical OUT as SPDIF: 1=yes, 0=no */
-#define RME96xx_wsel            0x2000 /* use Wordclock as sync (overwrites master) */
-#define RME96xx_inp_0           0x4000 /* SPDIF-IN 00=optical (ADAT1), */
-#define RME96xx_inp_1           0x8000 /* 01=coaxial (Cinch), 10=internal CDROM */
-
-#define RME96xx_SyncRef0       0x10000 /* preferred sync-source in autosync */
-#define RME96xx_SyncRef1       0x20000 /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
-
-#define RME96xx_SPDIF_RESET    (1<<18) /* Rev 1.5+: h/w SPDIF receiver */
-#define RME96xx_SPDIF_SELECT   (1<<19)
-#define RME96xx_SPDIF_CLOCK    (1<<20)
-#define RME96xx_SPDIF_WRITE    (1<<21)
-#define RME96xx_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */
-
-
-#define RME96xx_ctrl_init            (RME96xx_latency0 |\
-                                     RME96xx_Master |\
-                                     RME96xx_inp_1)
-                              
-
-
-/* Control register fields and shortcuts */
-
-#define RME96xx_latency (RME96xx_latency0|RME96xx_latency1|RME96xx_latency2)
-#define RME96xx_inp         (RME96xx_inp_0|RME96xx_inp_1)
-#define RME96xx_SyncRef    (RME96xx_SyncRef0|RME96xx_SyncRef1)
-#define RME96xx_mixer_allowed (RME96xx_Master|RME96xx_PRO|RME96xx_EMP|RME96xx_Dolby|RME96xx_opt_out|RME96xx_wsel|RME96xx_inp|RME96xx_SyncRef|RME96xx_ADAT1_INTERNAL)
-
-/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit1  (??? HP20020201) */
-
-#define RME96xx_SET_LATENCY(x)   (((x)&0x7)<<1)
-#define RME96xx_GET_LATENCY(x)   (((x)>>1)&0x7)
-#define RME96xx_SET_inp(x) (((x)&0x3)<<14)
-#define RME96xx_GET_inp(x)   (((x)>>14)&0x3)
-#define RME96xx_SET_SyncRef(x) (((x)&0x3)<<17)
-#define RME96xx_GET_SyncRef(x)   (((x)>>17)&0x3)
-
-
-/* buffer sizes */
-#define RME96xx_BYTES_PER_SAMPLE  4 /* sizeof(u32) */
-#define RME_16K 16*1024
-
-#define RME96xx_DMA_MAX_SAMPLES  (RME_16K)
-#define RME96xx_DMA_MAX_SIZE     (RME_16K * RME96xx_BYTES_PER_SAMPLE)
-#define RME96xx_DMA_MAX_SIZE_ALL (RME96xx_DMA_MAX_SIZE * RME96xx_CHANNELS_PER_CARD)
-
-#define RME96xx_NUM_OF_FRAGMENTS     2
-#define RME96xx_FRAGMENT_MAX_SIZE    (RME96xx_DMA_MAX_SIZE/2)
-#define RME96xx_FRAGMENT_MAX_SAMPLES (RME96xx_DMA_MAX_SAMPLES/2)
-#define RME96xx_MAX_LATENCY       7   /* 16k samples */
-
-
-#define RME96xx_MAX_DEVS 4 /* we provide some OSS stereodevs */
-#define RME96xx_MASK_DEVS 0x3 /* RME96xx_MAX_DEVS-1 */
-
-#define RME_MESS "rme96xx:"
-/*------------------------------------------------------------------------ 
-                  Types, struct and function declarations 
- ------------------------------------------------------------------------*/
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT RME_MESS" invalid magic value\n";
-
-#define VALIDATE_STATE(s)                         \
-({                                                \
-	if (!(s) || (s)->magic != RME96xx_MAGIC) { \
-		printk(invalid_magic);            \
-		return -ENXIO;                    \
-	}                                         \
-})
-
-/* --------------------------------------------------------------------- */
-
-
-static struct file_operations rme96xx_audio_fops;
-static struct file_operations rme96xx_mixer_fops;
-static int numcards;
-
-typedef int32_t raw_sample_t;
-
-typedef struct _rme96xx_info {
-
-	/* hardware settings */
-	int magic;
-	struct pci_dev * pcidev; /* pci_dev structure */
-	unsigned long __iomem *iobase;	
-	unsigned int irq;
-
-	/* list of rme96xx devices */
-	struct list_head devs;
-
-	spinlock_t lock;
-
-	u32 *recbuf;             /* memory for rec buffer */
-	u32 *playbuf;            /* memory for play buffer */
-
-	u32 control_register;
-
-	u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */
-
-	int hw_rev;             /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */
-	char *card_name;	/* hammerfall or hammerfall light names */
-
-	int open_count;         /* unused ???   HP20020201 */
-
-	int rate;
-	int latency;
-	unsigned int fragsize;
-	int started;
-
-	int hwptr; /* can be negativ because of pci burst offset  */
-	unsigned int hwbufid;  /* set by interrupt, buffer which is written/read now */
-	
-	struct dmabuf {
-
-		unsigned int format;
-		int formatshift;
-		int inchannels;       /* number of channels for device */
-		int outchannels;       /* number of channels for device */
-		int mono; /* if true, we play mono on 2 channels */
-		int inoffset; /* which channel is considered the first one */
-         	int outoffset;
-		
-		/* state */
-		int opened;               /* open() made */
-		int started;              /* first write/read */
-		int mmapped;              /* mmap */
-		int open_mode;
-
-		struct _rme96xx_info *s;  
-
-		/* pointer to read/write position in buffer */
-		unsigned readptr;          
-		unsigned writeptr;          
-
-		unsigned error; /* over/underruns cleared on sync again */
-
-		/* waiting and locking */
-		wait_queue_head_t wait;
-		struct mutex  open_mutex;
-		wait_queue_head_t open_wait;
-
-	} dma[RME96xx_MAX_DEVS]; 
-
-	int dspnum[RME96xx_MAX_DEVS];  /* register with sound subsystem */ 
-	int mixer;  /* register with sound subsystem */ 
-} rme96xx_info;
-
-
-/* fiddling with the card (first level hardware control) */
-
-static inline void rme96xx_set_ctrl(rme96xx_info* s,int mask)
-{
-
-	s->control_register|=mask;
-	writel(s->control_register,s->iobase + RME96xx_control_register);
-
-}
-
-static inline void rme96xx_unset_ctrl(rme96xx_info* s,int mask)
-{
-
-	s->control_register&=(~mask);
-	writel(s->control_register,s->iobase + RME96xx_control_register);
-
-}
-
-static inline int rme96xx_get_sample_rate_status(rme96xx_info* s)
-{
-	int val;
-	u32 status;
-	status = readl(s->iobase + RME96xx_status_register);
-	val = (status & RME96xx_fs48) ? 48000 : 44100;
-	if (status & RME96xx_DS_rd)
-		val *= 2;
-	return val;
-}
-
-static inline int rme96xx_get_sample_rate_ctrl(rme96xx_info* s)
-{
-	int val;
-	val = (s->control_register & RME96xx_freq) ? 48000 : 44100;
-	if (s->control_register & RME96xx_DS)
-		val *= 2;
-	return val;
-}
-
-
-/* code from ALSA card-rme9652.c for rev 1.5 SPDIF receiver   HP 20020201 */
-
-static void rme96xx_spdif_set_bit (rme96xx_info* s, int mask, int onoff)
-{
-	if (onoff) 
-		s->control_register |= mask;
-	else 
-		s->control_register &= ~mask;
-		
-	writel(s->control_register,s->iobase + RME96xx_control_register);
-}
-
-static void rme96xx_spdif_write_byte (rme96xx_info* s, const int val)
-{
-	long mask;
-	long i;
-
-	for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
-		if (val & mask)
-			rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 1);
-		else 
-			rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 0);
-
-		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
-		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
-	}
-}
-
-static int rme96xx_spdif_read_byte (rme96xx_info* s)
-{
-	long mask;
-	long val;
-	long i;
-
-	val = 0;
-
-	for (i = 0, mask = 0x80;  i < 8; i++, mask >>= 1) {
-		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
-		if (readl(s->iobase + RME96xx_status_register) & RME96xx_SPDIF_READ)
-			val |= mask;
-		rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
-	}
-
-	return val;
-}
-
-static void rme96xx_write_spdif_codec (rme96xx_info* s, const int address, const int data)
-{
-	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
-	rme96xx_spdif_write_byte (s, 0x20);
-	rme96xx_spdif_write_byte (s, address);
-	rme96xx_spdif_write_byte (s, data);
-	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
-}
-
-
-static int rme96xx_spdif_read_codec (rme96xx_info* s, const int address)
-{
-	int ret;
-
-	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
-	rme96xx_spdif_write_byte (s, 0x20);
-	rme96xx_spdif_write_byte (s, address);
-	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
-	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
-
-	rme96xx_spdif_write_byte (s, 0x21);
-	ret = rme96xx_spdif_read_byte (s);
-	rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
-
-	return ret;
-}
-
-static void rme96xx_initialize_spdif_receiver (rme96xx_info* s)
-{
-	/* XXX what unsets this ? */
-	/* no idea ???   HP 20020201 */
-
-	s->control_register |= RME96xx_SPDIF_RESET;
-
-	rme96xx_write_spdif_codec (s, 4, 0x40);
-	rme96xx_write_spdif_codec (s, 17, 0x13);
-	rme96xx_write_spdif_codec (s, 6, 0x02);
-}
-
-static inline int rme96xx_spdif_sample_rate (rme96xx_info *s, int *spdifrate)
-{
-	unsigned int rate_bits;
-
-	*spdifrate = 0x1;
-	if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) {
-		return -1;	/* error condition */
-	}
-	
-	if (s->hw_rev == 15) {
-
-		int x, y, ret;
-		
-		x = rme96xx_spdif_read_codec (s, 30);
-
-		if (x != 0) 
-			y = 48000 * 64 / x;
-		else
-			y = 0;
-
-		if      (y > 30400 && y < 33600)  {ret = 32000; *spdifrate = 0x7;}
-		else if (y > 41900 && y < 46000)  {ret = 44100; *spdifrate = 0x6;}
-		else if (y > 46000 && y < 50400)  {ret = 48000; *spdifrate = 0x5;}
-		else if (y > 60800 && y < 67200)  {ret = 64000; *spdifrate = 0x0;}
-		else if (y > 83700 && y < 92000)  {ret = 88200; *spdifrate = 0x4;}
-		else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;}
-		else                              {ret = 0; *spdifrate = 0x1;}
-		return ret;
-	}
-
-	rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F;
-
-	switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) {
-	case 0x7:
-		return 32000;
-		break;
-
-	case 0x6:
-		return 44100;
-		break;
-
-	case 0x5:
-		return 48000;
-		break;
-
-	case 0x4:
-		return 88200;
-		break;
-
-	case 0x3:
-		return 96000;
-		break;
-
-	case 0x0:
-		return 64000;
-		break;
-
-	default:
-		/* was an ALSA warning ...
-		  snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n",
-		  s->card_name, rate_bits);
-		*/
-		return 0;
-		break;
-	}
-}
-
-/* end of code from ALSA card-rme9652.c */
-
-
-
-/* the hwbuf in the status register seems to have some jitter, to get rid of
-   it, we first only let the numbers grow, to be on the secure side we 
-   subtract a certain amount RME96xx_BURSTBYTES from the resulting number */
-
-/* the function returns the hardware pointer in bytes */
-#define RME96xx_BURSTBYTES -64  /* bytes by which hwptr could be off */
-
-static inline int rme96xx_gethwptr(rme96xx_info* s,int exact)
-{
-	unsigned long flags;
-	if (exact) {
-		unsigned int hwp;
-/* the hwptr seems to be rather unreliable :(, so we don't use it */
-		spin_lock_irqsave(&s->lock,flags);
-		
-		hwp  = readl(s->iobase + RME96xx_status_register) & 0xffc0;
-		s->hwptr = (hwp < s->hwptr) ? s->hwptr : hwp;
-//		s->hwptr = hwp;
-
-		spin_unlock_irqrestore(&s->lock,flags);
-		return (s->hwptr+RME96xx_BURSTBYTES) & ((s->fragsize<<1)-1);
-	}
-	return (s->hwbufid ? s->fragsize : 0);
-}
-
-static inline void rme96xx_setlatency(rme96xx_info* s,int l)
-{
-	s->latency = l;
-	s->fragsize = 1<<(8+l);
-	rme96xx_unset_ctrl(s,RME96xx_latency);
-	rme96xx_set_ctrl(s,RME96xx_SET_LATENCY(l));	
-}
-
-
-static void rme96xx_clearbufs(struct dmabuf* dma)
-{
-	int i,j;
-	unsigned long flags;
-
-	/* clear dmabufs */
-	for(i=0;i<devices;i++) {
-		for (j=0;j<dma->outchannels + dma->mono;j++)
-			memset(&dma->s->playbuf[(dma->outoffset + j)*RME96xx_DMA_MAX_SAMPLES], 
-			       0, RME96xx_DMA_MAX_SIZE);
-	}
-	spin_lock_irqsave(&dma->s->lock,flags);
-	dma->writeptr = 0;
-	dma->readptr = 0;
-	spin_unlock_irqrestore(&dma->s->lock,flags);
-}
-
-static int rme96xx_startcard(rme96xx_info *s,int stop)
-{
-	int i;
-	unsigned long flags;
-
-	COMM       ("startcard");
-	if(s->control_register & RME96xx_IE){
-		/* disable interrupt first */
-		
-		rme96xx_unset_ctrl( s,RME96xx_start_bit );
-		udelay(10);
-		rme96xx_unset_ctrl( s,RME96xx_IE);
-		spin_lock_irqsave(&s->lock,flags); /* timing is critical */
-		s->started = 0;
-		spin_unlock_irqrestore(&s->lock,flags);
-		if (stop) {
-		     COMM("Sound card stopped");
-		     return 1;
-		}
-	}
-	COMM       ("interrupt disabled");
-	/* first initialize all pointers on card */
-	for(i=0;i<RME96xx_num_of_init_regs;i++){
-		writel(0,s->iobase + i);
-		udelay(10); /* ?? */
-	}
-	COMM       ("regs cleaned");
-
-	spin_lock_irqsave(&s->lock,flags); /* timing is critical */
-	udelay(10);
-	s->started = 1;
-	s->hwptr = 0;
-	spin_unlock_irqrestore(&s->lock,flags);
-
-	rme96xx_set_ctrl( s, RME96xx_IE | RME96xx_start_bit);
-
-
-	COMM("Sound card started");
-  
-	return 1;
-}
-
-
-static inline int rme96xx_getospace(struct dmabuf * dma, unsigned int hwp)
-{
-	int cnt;
-	int  swptr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dma->s->lock,flags); 
-	swptr = dma->writeptr;
-	cnt = (hwp - swptr);
-	
-	if (cnt < 0) {
-	     cnt = ((dma->s->fragsize<<1) - swptr);
-	}
-	spin_unlock_irqrestore(&dma->s->lock,flags);
-	return cnt;
-}
-
-static inline int rme96xx_getispace(struct dmabuf * dma, unsigned int hwp)
-{
-	int cnt;
-	int  swptr;
-	unsigned long flags;
-
-	spin_lock_irqsave(&dma->s->lock,flags); 
-	swptr = dma->readptr;
-	cnt = (hwp - swptr);
-	 
-	if (cnt < 0) {
-		cnt = ((dma->s->fragsize<<1) - swptr);
-	}
-	spin_unlock_irqrestore(&dma->s->lock,flags);
-	return cnt;
-}
-
-
-static inline int rme96xx_copyfromuser(struct dmabuf* dma,const char __user * buffer,int count,int hop)
-{
-	int swptr = dma->writeptr;
-	switch (dma->format) {
-	case AFMT_S32_BLOCKED:
-	{
-	     char __user * buf = (char __user *)buffer;
-	     int cnt = count/dma->outchannels;
-	     int i;
-	     for (i=0;i < dma->outchannels;i++) {
-		  char* hwbuf =(char*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];
-		  hwbuf+=swptr;
-
-		  if (copy_from_user(hwbuf,buf, cnt))
-		       return -1;
-		  buf+=hop;
-	     }
-	     swptr+=cnt;
-	     break;
-	}
-	case AFMT_S16_LE:
-	{
-	     int i,j;
-	     int cnt = count/dma->outchannels;
-	     for (i=0;i < dma->outchannels + dma->mono;i++) {
-		     short __user * sbuf = (short __user *)buffer + i*(!dma->mono);
-		     short* hwbuf =(short*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];	     
-		     hwbuf+=(swptr>>1);
-		     for (j=0;j<(cnt>>1);j++) {
-			     hwbuf++; /* skip the low 16 bits */
-			     __get_user(*hwbuf++,sbuf++);
-			     sbuf+=(dma->outchannels-1);
-		     }
-	     }
-	     swptr += (cnt<<1);
-	     break;
-	}
-	default:
-	     printk(RME_MESS" unsupported format\n");
-	     return -1;
-	} /* switch */
-
-	swptr&=((dma->s->fragsize<<1) -1);
-	dma->writeptr = swptr;
-
-	return 0;
-}
-
-/* The count argument is the number of bytes */
-static inline int rme96xx_copytouser(struct dmabuf* dma,const char __user* buffer,int count,int hop)
-{
-	int swptr = dma->readptr;
-	switch (dma->format) {
-	case AFMT_S32_BLOCKED:
-	{
-	     char __user * buf = (char __user *)buffer;
-	     int cnt = count/dma->inchannels;
-	     int i;
-
-	     for (i=0;i < dma->inchannels;i++) {
-		  char* hwbuf =(char*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];
-		  hwbuf+=swptr;
-
-		  if (copy_to_user(buf,hwbuf,cnt))
-		       return -1;
-		  buf+=hop;
-	     }
-	     swptr+=cnt;
-	     break;
-	}
-	case AFMT_S16_LE:
-	{
-	     int i,j;
-	     int cnt = count/dma->inchannels;
-	     for (i=0;i < dma->inchannels;i++) {
-		  short __user * sbuf = (short __user *)buffer + i;
-		  short* hwbuf =(short*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];	     
-		  hwbuf+=(swptr>>1);
-		  for (j=0;j<(cnt>>1);j++) {
-		       hwbuf++;
-		       __put_user(*hwbuf++,sbuf++);
-		       sbuf+=(dma->inchannels-1);
-		  }
-	     }
-	     swptr += (cnt<<1);
-	     break;
-	}
-	default:
-	     printk(RME_MESS" unsupported format\n");
-	     return -1;
-	} /* switch */
-	
-	swptr&=((dma->s->fragsize<<1) -1);	
-	dma->readptr = swptr;
-	return 0;
-}
-
-
-static irqreturn_t rme96xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	int i;
-	rme96xx_info *s = (rme96xx_info *)dev_id;
-	struct dmabuf *db;
-	u32 status;
-	unsigned long flags;
-
-	status = readl(s->iobase + RME96xx_status_register);
-	if (!(status & RME96xx_IRQ)) {
-		return IRQ_NONE;
-	}
-
-	spin_lock_irqsave(&s->lock,flags);
-	writel(0,s->iobase + RME96xx_irq_clear);
-
-	s->hwbufid = (status & RME96xx_buffer_id)>>26;	
-	if ((status & 0xffc0) <= 256) s->hwptr = 0; 
-	for(i=0;i<devices;i++)
-	{
-		db = &(s->dma[i]);
-		if(db->started > 0)
-			wake_up(&(db->wait));		
-	}  
-	spin_unlock_irqrestore(&s->lock,flags);
-	return IRQ_HANDLED;
-}
-
-
-
-/*---------------------------------------------------------------------------- 
- PCI detection and module initialization stuff 
- ----------------------------------------------------------------------------*/
-
-static void* busmaster_malloc(int size) {
-     int pg; /* 2 s exponent of memory size */
-        char *buf;
-
-        DBG(printk("kernel malloc pages ..\n"));
-        
-        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-
-        buf = (char *) __get_free_pages(GFP_KERNEL | GFP_DMA, pg);
-
-        if (buf) {
-                struct page* page, *last_page;
-
-                page = virt_to_page(buf);
-                last_page = page + (1 << pg);
-                DBG(printk("setting reserved bit\n"));
-                while (page < last_page) {
-			SetPageReserved(page);
-                        page++;
-                }
-		return buf;
-        }
-	DBG(printk("allocated %ld",(long)buf));
-	return NULL;
-}
-
-static void busmaster_free(void* ptr,int size) {
-        int pg;
-	struct page* page, *last_page;
-
-        if (ptr == NULL)
-                return;
-
-        for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-
-        page = virt_to_page(ptr);
-        last_page = page + (1 << pg);
-        while (page < last_page) {
-		ClearPageReserved(page);
-		page++;
-	}
-	DBG(printk("freeing pages\n"));
-        free_pages((unsigned long) ptr, pg);
-	DBG(printk("done\n"));
-}
-
-/* initialize those parts of the info structure which are not pci detectable resources */
-
-static int rme96xx_dmabuf_init(rme96xx_info * s,struct dmabuf* dma,int ioffset,int ooffset) {
-
-	mutex_init(&dma->open_mutex);
-	init_waitqueue_head(&dma->open_wait);
-	init_waitqueue_head(&dma->wait);
-	dma->s = s; 
-	dma->error = 0;
-
-	dma->format = AFMT_S32_BLOCKED;
-	dma->formatshift = 0;
-	dma->inchannels = dma->outchannels = 1;
-	dma->inoffset = ioffset;
-	dma->outoffset = ooffset;
-
-	dma->opened=0;
-	dma->started=0;
-	dma->mmapped=0;
-	dma->open_mode=0;
-	dma->mono=0;
-
-	rme96xx_clearbufs(dma);
-	return 0;
-}
-
-
-static int rme96xx_init(rme96xx_info* s)
-{
-	int i;
-	int status;
-	unsigned short rev;
-
-	DBG(printk("%s\n", __FUNCTION__));
-	numcards++;
-
-	s->magic = RME96xx_MAGIC; 
-
-	spin_lock_init(&s->lock);
-
-	COMM            ("setup busmaster memory")
-	s->recbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
-	s->playbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
-
-	if (!s->recbuf || !s->playbuf) {
-		printk(KERN_ERR RME_MESS" Unable to allocate busmaster memory\n");
-		return -ENODEV;
-	}
-
-	COMM            ("setting rec and playbuffers")
-
-	writel((u32) virt_to_bus(s->recbuf),s->iobase + RME96xx_rec_buffer);
-  	writel((u32) virt_to_bus(s->playbuf),s->iobase + RME96xx_play_buffer);
-
-	COMM             ("initializing control register")
-	rme96xx_unset_ctrl(s,0xffffffff);
-	rme96xx_set_ctrl(s,RME96xx_ctrl_init);
-
-
-	COMM              ("setup devices")	
-	for (i=0;i < devices;i++) {
-		struct dmabuf * dma = &s->dma[i];
-		rme96xx_dmabuf_init(s,dma,2*i,2*i);
-	}
-
-	/* code from ALSA card-rme9652.c   HP 20020201 */
-        /* Determine the h/w rev level of the card. This seems like
-	   a particularly kludgy way to encode it, but its what RME
-	   chose to do, so we follow them ...
-	*/
-
-	status = readl(s->iobase + RME96xx_status_register);
-	if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) {
-		s->hw_rev = 15;
-	} else {
-		s->hw_rev = 11;
-	}
-
-	/* Differentiate between the standard Hammerfall, and the
-	   "Light", which does not have the expansion board. This
-	   method comes from information received from Mathhias
-	   Clausen at RME. Display the EEPROM and h/w revID where
-	   relevant.  
-	*/
-
-	pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev);
-	switch (rev & 0xff) {
-	case 8: /* original eprom */
-		if (s->hw_rev == 15) {
-			s->card_name = "RME Digi9636 (Rev 1.5)";
-		} else {
-			s->card_name = "RME Digi9636";
-		}
-		break;
-	case 9: /* W36_G EPROM */
-		s->card_name = "RME Digi9636 (Rev G)";
-		break;
-	case 4: /* W52_G EPROM */
-		s->card_name = "RME Digi9652 (Rev G)";
-		break;
-	default:
-	case 3: /* original eprom */
-		if (s->hw_rev == 15) {
-			s->card_name = "RME Digi9652 (Rev 1.5)";
-		} else {
-			s->card_name = "RME Digi9652";
-		}
-		break;
-	}
-
-	printk(KERN_INFO RME_MESS" detected %s (hw_rev %d)\n",s->card_name,s->hw_rev); 
-
-	if (s->hw_rev == 15)
-		rme96xx_initialize_spdif_receiver (s);
-
-	s->started = 0;
-	rme96xx_setlatency(s,7);
-
-	printk(KERN_INFO RME_MESS" card %d initialized\n",numcards); 
-	return 0;
-}
-
-
-/* open uses this to figure out which device was opened .. this seems to be 
-   unnecessary complex */
-
-static LIST_HEAD(devs);
-
-static int __devinit rme96xx_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
-	int i;
-	rme96xx_info *s;
-
-	DBG(printk("%s\n", __FUNCTION__));
-	
-	if (pcidev->irq == 0) 
-		return -1;
-	if (!pci_dma_supported(pcidev, 0xffffffff)) {
-		printk(KERN_WARNING RME_MESS" architecture does not support 32bit PCI busmaster DMA\n");
-		return -1;
-	}
-	if (!(s = kmalloc(sizeof(rme96xx_info), GFP_KERNEL))) {
-		printk(KERN_WARNING RME_MESS" out of memory\n");
-		return -1;
-	}
-	memset(s, 0, sizeof(rme96xx_info));
-
-	s->pcidev = pcidev;
-	s->iobase = ioremap(pci_resource_start(pcidev, 0),RME96xx_IO_EXTENT);
-	s->irq = pcidev->irq;
-
-        DBG(printk("remapped iobase: %lx irq %d\n",(long)s->iobase,s->irq));
-
-	if (pci_enable_device(pcidev))
-		goto err_irq;
-	if (request_irq(s->irq, rme96xx_interrupt, IRQF_SHARED, "rme96xx", s)) {
-		printk(KERN_ERR RME_MESS" irq %u in use\n", s->irq);
-		goto err_irq;
-	}
-	
-	/* initialize the card */
-
-	i = 0;
-	if (rme96xx_init(s) < 0) {
-		printk(KERN_ERR RME_MESS" initialization failed\n");
-		goto err_devices;
-	}
-	for (i=0;i<devices;i++) {
-		if ((s->dspnum[i] = register_sound_dsp(&rme96xx_audio_fops, -1)) < 0)
-			goto err_devices;
-	}
-
-	if ((s->mixer = register_sound_mixer(&rme96xx_mixer_fops, -1)) < 0)
-		goto err_devices;
-
-	pci_set_drvdata(pcidev, s);
-	pcidev->dma_mask = 0xffffffff; /* ????? */
-	/* put it into driver list */
-	list_add_tail(&s->devs, &devs);
-
-	DBG(printk("initialization successful\n"));
-	return 0;
-
-	/* error handler */
- err_devices:
-	while (i--) 
-		unregister_sound_dsp(s->dspnum[i]);
-	free_irq(s->irq,s);
- err_irq:
-	kfree(s);
-	return -1;
-}
-
-
-static void __devexit rme96xx_remove(struct pci_dev *dev)
-{
-	int i;
-	rme96xx_info *s = pci_get_drvdata(dev);
-
-	if (!s) {
-		printk(KERN_ERR"device structure not valid\n");
-		return ;
-	}
-
-	if (s->started) rme96xx_startcard(s,0);
-
-	i = devices;
-	while (i) {
-		i--;
-		unregister_sound_dsp(s->dspnum[i]);
-	}
-	
-	unregister_sound_mixer(s->mixer);
-	synchronize_irq(s->irq);
-	free_irq(s->irq,s);
-	busmaster_free(s->recbuf,RME96xx_DMA_MAX_SIZE_ALL);
-	busmaster_free(s->playbuf,RME96xx_DMA_MAX_SIZE_ALL);
-	kfree(s);
-	pci_set_drvdata(dev, NULL);
-}
-
-
-#ifndef PCI_VENDOR_ID_RME 
-#define PCI_VENDOR_ID_RME 0x10ee
-#endif
-#ifndef PCI_DEVICE_ID_RME9652
-#define PCI_DEVICE_ID_RME9652 0x3fc4
-#endif
-#ifndef PCI_ANY_ID
-#define PCI_ANY_ID 0
-#endif
-
-static struct pci_device_id id_table[] = {
-	{
-		.vendor	   = PCI_VENDOR_ID_RME,
-		.device	   = PCI_DEVICE_ID_RME9652,
-		.subvendor = PCI_ANY_ID,
-		.subdevice = PCI_ANY_ID,
-	},
-	{ 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver rme96xx_driver = {
-	.name	  =  "rme96xx",
-	.id_table = id_table,
-	.probe	  = rme96xx_probe,
-	.remove	  = __devexit_p(rme96xx_remove),
-};
-
-static int __init init_rme96xx(void)
-{
-	printk(KERN_INFO RME_MESS" version "RMEVERSION" time " __TIME__ " " __DATE__ "\n");
-	devices = ((devices-1) & RME96xx_MASK_DEVS) + 1;
-	printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices);
-        numcards = 0;
-	return pci_register_driver(&rme96xx_driver);
-}
-
-static void __exit cleanup_rme96xx(void)
-{
-	printk(KERN_INFO RME_MESS" unloading\n");
-	pci_unregister_driver(&rme96xx_driver);
-}
-
-module_init(init_rme96xx);
-module_exit(cleanup_rme96xx);
-
-
-
-
-
-/*-------------------------------------------------------------------------- 
-   Implementation of file operations 
----------------------------------------------------------------------------*/
-
-#define RME96xx_FMT (AFMT_S16_LE|AFMT_U8|AFMT_S32_BLOCKED)
-/* AFTM_U8 is not (yet?) supported ...  HP20020201 */
-
-static int rme96xx_ioctl(struct inode *in, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct dmabuf * dma = (struct dmabuf *)file->private_data; 
-	rme96xx_info *s = dma->s;
-	unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
-	int count;
-	int val = 0;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	VALIDATE_STATE(s);
-
-	DBG(printk("ioctl %ud\n",cmd));
-
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-#if 0
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
-#endif
-		return 0;
-		
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-		
-        case SNDCTL_DSP_RESET:
-//		rme96xx_clearbufs(dma);
-		return 0;
-
-        case SNDCTL_DSP_SPEED:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-/* generally it's not a problem if we change the speed 
-			if (dma->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
-				return -EINVAL;
-*/
-			spin_lock_irqsave(&s->lock, flags);
-
-			switch (val) {
-			case 44100:
-			case 88200:
-				rme96xx_unset_ctrl(s,RME96xx_freq);
-				break;
-			case 48000: 
-			case 96000: 
-				rme96xx_set_ctrl(s,RME96xx_freq);
-				break;
-			/* just report current rate as default
-			   e.g. use 0 to "select" current digital input rate
-			default:
-				rme96xx_unset_ctrl(s,RME96xx_freq);
-				val = 44100;
-			*/
-			}
-			if (val > 50000)
-				rme96xx_set_ctrl(s,RME96xx_DS);
-			else
-				rme96xx_unset_ctrl(s,RME96xx_DS);
-			/* set val to actual value  HP 20020201 */
-			/* NOTE: if not "Sync Master", reported rate might be not yet "updated" ... but I don't want to insert a long udelay() here */
-			if ((s->control_register & RME96xx_Master) && !(s->control_register & RME96xx_wsel))
-				val = rme96xx_get_sample_rate_ctrl(s);
-			else
-				val = rme96xx_get_sample_rate_status(s);
-			s->rate = val;
-			spin_unlock_irqrestore(&s->lock, flags);
-		}
-		DBG(printk("speed set to %d\n",val));
-		return put_user(val, p);
-		
-        case SNDCTL_DSP_STEREO: /* this plays a mono file on two channels */
-                if (get_user(val, p))
-			return -EFAULT;
-		
-		if (!val) {
-			DBG(printk("setting to mono\n")); 
-			dma->mono=1; 
-			dma->inchannels = 1;
-			dma->outchannels = 1;
-		}
-		else {
-			DBG(printk("setting to stereo\n")); 
-			dma->mono = 0;
-			dma->inchannels = 2;
-			dma->outchannels = 2;
-		}
-		return 0;
-        case SNDCTL_DSP_CHANNELS:
-		/* remember to check for resonable offset/channel pairs here */
-                if (get_user(val, p))
-			return -EFAULT;
-
-		if (file->f_mode & FMODE_WRITE) { 			
-			if (val > 0 && (dma->outoffset + val) <= RME96xx_CHANNELS_PER_CARD) 
-				dma->outchannels = val;
-			else
-				dma->outchannels = val = 2;
-			DBG(printk("setting to outchannels %d\n",val)); 
-		}
-		if (file->f_mode & FMODE_READ) {
-			if (val > 0 && (dma->inoffset + val) <= RME96xx_CHANNELS_PER_CARD) 
-				dma->inchannels = val;
-			else
-				dma->inchannels = val = 2;
-			DBG(printk("setting to inchannels %d\n",val)); 
-		}
-
-		dma->mono=0;
-
-		return put_user(val, p);
-		
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(RME96xx_FMT, p);
-		
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		DBG(printk("setting to format %x\n",val)); 
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			if (val & RME96xx_FMT)
-				dma->format = val;
-			switch (dma->format) {
-			case AFMT_S16_LE:
-				dma->formatshift=1;
-				break;
-			case AFMT_S32_BLOCKED:
-				dma->formatshift=0;
-				break;
-			}
-		}
-		return put_user(dma->format, p);
-		
-	case SNDCTL_DSP_POST:
-                return 0;
-
-        case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-#if 0
-		if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN) 
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN) 
-			val |= PCM_ENABLE_OUTPUT;
-#endif
-		return put_user(val, p);
-		
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-#if 0
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
-					return ret;
-				start_adc(s);
-			} else
-				stop_adc(s);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
-					return ret;
-				start_dac2(s);
-			} else
-				stop_dac2(s);
-		}
-#endif
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-
-		val = rme96xx_gethwptr(dma->s,0);
-
-
-		count = rme96xx_getospace(dma,val);
-		if (!s->started) count = s->fragsize*2;
-		abinfo.fragsize =(s->fragsize*dma->outchannels)>>dma->formatshift;
-                abinfo.bytes = (count*dma->outchannels)>>dma->formatshift;
-                abinfo.fragstotal = 2;
-                abinfo.fragments = (count > s->fragsize); 
-
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-
-		val = rme96xx_gethwptr(dma->s,0);
-
-		count = rme96xx_getispace(dma,val);
-
-		abinfo.fragsize = (s->fragsize*dma->inchannels)>>dma->formatshift;
-                abinfo.bytes = (count*dma->inchannels)>>dma->formatshift;
-                abinfo.fragstotal = 2;
-                abinfo.fragments = count > s->fragsize; 
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-		
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_GETODELAY: /* What should this exactly do ? ,
-				      ATM it is just abinfo.bytes */
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-
-		val = rme96xx_gethwptr(dma->s,0);
-		count = val - dma->readptr;
-		if (count < 0)
-			count += s->fragsize<<1;
-
-		return put_user(count, p);
-
-
-/* check out how to use mmaped mode (can only be blocked !!!) */
-        case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		val = rme96xx_gethwptr(dma->s,0);
-		spin_lock_irqsave(&s->lock,flags);
-                cinfo.bytes = s->fragsize<<1;
-		count = val - dma->readptr;
-		if (count < 0)
-			count += s->fragsize<<1;
-
-                cinfo.blocks = (count > s->fragsize); 
-                cinfo.ptr = val;
-		if (dma->mmapped)
-			dma->readptr &= s->fragsize<<1;
-		spin_unlock_irqrestore(&s->lock,flags);
-
-                if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		val = rme96xx_gethwptr(dma->s,0);
-		spin_lock_irqsave(&s->lock,flags);
-                cinfo.bytes = s->fragsize<<1;
-		count = val - dma->writeptr;
-		if (count < 0)
-			count += s->fragsize<<1;
-
-                cinfo.blocks = (count > s->fragsize); 
-                cinfo.ptr = val;
-		if (dma->mmapped)
-			dma->writeptr &= s->fragsize<<1;
-		spin_unlock_irqrestore(&s->lock,flags);
-                if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-        case SNDCTL_DSP_GETBLKSIZE:
-	     return put_user(s->fragsize, p);
-
-        case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, p))
-			return -EFAULT;
-		val&=0xffff;
-		val -= 7;
-		if (val < 0) val = 0;
-		if (val > 7) val = 7;
-		rme96xx_setlatency(s,val);
-		return 0;
-
-        case SNDCTL_DSP_SUBDIVIDE:
-#if 0
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
-			return -EINVAL;
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			s->dma_dac2.subdivision = val;
-#endif		
-		return 0;
-
-        case SOUND_PCM_READ_RATE:
-		/* HP20020201 */
-		s->rate = rme96xx_get_sample_rate_status(s);
-		return put_user(s->rate, p);
-
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user(dma->outchannels, p);
-
-        case SOUND_PCM_READ_BITS:
-		switch (dma->format) {
-			case AFMT_S32_BLOCKED:
-				val = 32;
-				break;
-			case AFMT_S16_LE:
-				val = 16;
-				break;
-		}
-		return put_user(val, p);
-
-        case SOUND_PCM_WRITE_FILTER:
-        case SNDCTL_DSP_SETSYNCRO:
-        case SOUND_PCM_READ_FILTER:
-                return -EINVAL;
-		
-	}
-
-
-	return -ENODEV;
-}
-
-
-
-static int rme96xx_open(struct inode *in, struct file *f)
-{
-	int minor = iminor(in);
-	struct list_head *list;
-	int devnum;
-	rme96xx_info *s;
-	struct dmabuf* dma;
-	DECLARE_WAITQUEUE(wait, current); 
-
-	DBG(printk("device num %d open\n",devnum));
-
-	nonseekable_open(in, f);
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, rme96xx_info, devs);
-		for (devnum=0; devnum<devices; devnum++)
-			if (!((s->dspnum[devnum] ^ minor) & ~0xf)) 
-				break;
-		if (devnum<devices)
-			break;
-	}
-       	VALIDATE_STATE(s);
-
-	dma = &s->dma[devnum];
-	f->private_data = dma;
-	/* wait for device to become free */
-	mutex_lock(&dma->open_mutex);
-	while (dma->open_mode & f->f_mode) {
-		if (f->f_flags & O_NONBLOCK) {
-			mutex_unlock(&dma->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&dma->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&dma->open_mutex);
-		schedule();
-		remove_wait_queue(&dma->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&dma->open_mutex);
-	}
-
-	COMM                ("hardware open")
-
-	if (!dma->opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset);
-
-	dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE));
-	dma->opened = 1;
-	mutex_unlock(&dma->open_mutex);
-
-	DBG(printk("device num %d open finished\n",devnum));
-	return 0;
-}
-
-static int rme96xx_release(struct inode *in, struct file *file)
-{
-	struct dmabuf * dma = (struct dmabuf*) file->private_data;
-	/* int hwp;  ... was unused   HP20020201 */
-	DBG(printk("%s\n", __FUNCTION__));
-
-	COMM          ("draining")
-	if (dma->open_mode & FMODE_WRITE) {
-#if 0 /* Why doesn't this work with some cards ?? */
-	     hwp = rme96xx_gethwptr(dma->s,0);
-	     while (rme96xx_getospace(dma,hwp)) {
-		  interruptible_sleep_on(&(dma->wait));
-		  hwp = rme96xx_gethwptr(dma->s,0);
-	     }
-#endif
-	     rme96xx_clearbufs(dma);
-	}
-
-	dma->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
-	if (!(dma->open_mode & (FMODE_READ|FMODE_WRITE))) {
-	     dma->opened = 0;
-	     if (dma->s->started) rme96xx_startcard(dma->s,1);
-	}
-
-	wake_up(&dma->open_wait);
-	mutex_unlock(&dma->open_mutex);
-
-	return 0;
-}
-
-
-static ssize_t rme96xx_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct dmabuf *dma = (struct dmabuf *)file->private_data;
-	ssize_t ret = 0;
-	int cnt; /* number of bytes from "buffer" that will/can be used */
-	int hop = count/dma->outchannels;
-	int hwp;
-	int exact = (file->f_flags & O_NONBLOCK); 
-
-
-	if(dma == NULL || (dma->s) == NULL) 
-		return -ENXIO;
-
-	if (dma->mmapped || !dma->opened)
-		return -ENXIO;
-
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-
-	if (! (dma->open_mode  & FMODE_WRITE))
-                return -ENXIO;
-
-	if (!dma->s->started) rme96xx_startcard(dma->s,exact);
-	hwp = rme96xx_gethwptr(dma->s,0);
-
-	if(!(dma->started)){		 
-		COMM          ("first write")
-			
-		dma->readptr = hwp;
-		dma->writeptr = hwp;
-		dma->started = 1;
-	}
-
-  	while (count > 0) {
-		cnt = rme96xx_getospace(dma,hwp);		
-		cnt>>=dma->formatshift;
-		cnt*=dma->outchannels;
-		if (cnt > count)
-			cnt = count;
-
-		if (cnt != 0) {
-		        if (rme96xx_copyfromuser(dma,buffer,cnt,hop))
-				return ret ? ret : -EFAULT;
-			count -= cnt;
-			buffer += cnt;
-			ret += cnt;
-			if (count == 0) return ret;
-		}
-		if (file->f_flags & O_NONBLOCK)
-			return ret ? ret : -EAGAIN;
-		
-		if ((hwp - dma->writeptr) <= 0) {
-			interruptible_sleep_on(&(dma->wait));
-			
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
-		}			
-
-		hwp = rme96xx_gethwptr(dma->s,exact);
-
-	}; /* count > 0 */
-
-	return ret;
-}
-
-static ssize_t rme96xx_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{ 
-	struct dmabuf *dma = (struct dmabuf *)file->private_data;
-	ssize_t ret = 0;
-	int cnt; /* number of bytes from "buffer" that will/can be used */
-	int hop = count/dma->inchannels;
-	int hwp;
-	int exact = (file->f_flags & O_NONBLOCK); 
-
-
-	if(dma == NULL || (dma->s) == NULL) 
-		return -ENXIO;
-
-	if (dma->mmapped || !dma->opened)
-		return -ENXIO;
-
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-
-	if (! (dma->open_mode  & FMODE_READ))
-                return -ENXIO;
-
-	if (!dma->s->started) rme96xx_startcard(dma->s,exact);
-	hwp = rme96xx_gethwptr(dma->s,0);
-
-	if(!(dma->started)){		 
-		COMM          ("first read")
-		     
-		dma->writeptr = hwp;
-		dma->readptr = hwp;
-		dma->started = 1;
-	}
-
-  	while (count > 0) {
-		cnt = rme96xx_getispace(dma,hwp);		
-		cnt>>=dma->formatshift;
-		cnt*=dma->inchannels;
-
-		if (cnt > count)
-			cnt = count;
-
-		if (cnt != 0) {
-		        
-			if (rme96xx_copytouser(dma,buffer,cnt,hop))
-				return ret ? ret : -EFAULT;
-			
-			count -= cnt;
-			buffer += cnt;
-			ret += cnt;
-			if (count == 0) return ret;
-		}
-		if (file->f_flags & O_NONBLOCK)
-			return ret ? ret : -EAGAIN;
-		
-		if ((hwp - dma->readptr) <= 0) {
-			interruptible_sleep_on(&(dma->wait));
-			
-			if (signal_pending(current))
-				return ret ? ret : -ERESTARTSYS;
-		}			
-		hwp = rme96xx_gethwptr(dma->s,exact);
-
-	}; /* count > 0 */
-
-	return ret;
-}
-
-static int rm96xx_mmap(struct file *file, struct vm_area_struct *vma) {
-	struct dmabuf *dma = (struct dmabuf *)file->private_data;
-	rme96xx_info* s = dma->s;
-	unsigned long size;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-
-	if (vma->vm_pgoff != 0) {
-		unlock_kernel();
-		return -EINVAL;
-	}
-	size = vma->vm_end - vma->vm_start;
-	if (size > RME96xx_DMA_MAX_SIZE) {
-		unlock_kernel();
-		return -EINVAL;
-	}
-
-
-	if (vma->vm_flags & VM_WRITE) {
-		if (!s->started) rme96xx_startcard(s,1);
-
-		if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
-			unlock_kernel();
-			return -EAGAIN;
-		}
-	} 
-	else if (vma->vm_flags & VM_READ) {
-		if (!s->started) rme96xx_startcard(s,1);
-		if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
-			unlock_kernel();
-			return -EAGAIN;
-		}
-	} else  {
-		unlock_kernel();
-		return -EINVAL;
-	}
-
-
-/* this is the mapping */
-	vma->vm_flags &= ~VM_IO;
-	dma->mmapped = 1;
-	unlock_kernel();
-	return 0;
-}
-
-static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct dmabuf *dma = (struct dmabuf *)file->private_data;
-	rme96xx_info* s = dma->s;
-	unsigned int mask = 0;
-	unsigned int hwp,cnt;
-
-        DBG(printk("rme96xx poll_wait ...\n"));
-	VALIDATE_STATE(s);
-
-	if (!s->started) {
-		  mask |= POLLOUT | POLLWRNORM;
-	}
-	poll_wait(file, &dma->wait, wait);
-
-	hwp = rme96xx_gethwptr(dma->s,0);
-
-        DBG(printk("rme96xx poll: ..cnt %d > %d\n",cnt,s->fragsize));	
-
-	cnt = rme96xx_getispace(dma,hwp);
-
-	if (file->f_mode & FMODE_READ) 
-	     if (cnt > 0)
-		  mask |= POLLIN | POLLRDNORM;
-
-
-
-	cnt = rme96xx_getospace(dma,hwp);
-
-	if (file->f_mode & FMODE_WRITE) 
-	     if (cnt > 0)
-		  mask |= POLLOUT | POLLWRNORM;
-
-
-//        printk("rme96xx poll_wait ...%d > %d\n",rme96xx_getospace(dma,hwp),rme96xx_getispace(dma,hwp));
-
-	return mask;
-}
-
-
-static struct file_operations rme96xx_audio_fops = {
-	.owner	 = THIS_MODULE,
-	.read	 = rme96xx_read,
-	.write	 = rme96xx_write,
-	.poll	 = rme96xx_poll,
-	.ioctl	 = rme96xx_ioctl,  
-	.mmap	 = rm96xx_mmap,
-	.open	 = rme96xx_open,  
-	.release = rme96xx_release 
-};
-
-static int rme96xx_mixer_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	struct list_head *list;
-	rme96xx_info *s;
-
-	COMM  ("mixer open");
-
-	nonseekable_open(inode, file);
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, rme96xx_info, devs);
-		if (s->mixer== minor)
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-
-	COMM                       ("mixer opened")
-	return 0;
-}
-
-static int rme96xx_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	rme96xx_info *s = (rme96xx_info *)file->private_data;
-	u32 status;
-	int spdifrate;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	status = readl(s->iobase + RME96xx_status_register);
-	/* hack to convert rev 1.5 SPDIF rate to "crystalrate" format   HP 20020201 */
-	rme96xx_spdif_sample_rate(s,&spdifrate);
-	status = (status & ~RME96xx_F) | ((spdifrate<<22) & RME96xx_F);
-
-	VALIDATE_STATE(s);
-	if (cmd == SOUND_MIXER_PRIVATE1) {
-		rme_mixer mixer;
-		if (copy_from_user(&mixer,argp,sizeof(mixer)))
-			return -EFAULT;
-		
-		mixer.devnr &= RME96xx_MASK_DEVS;
-		if (mixer.devnr >= devices)
-			mixer.devnr = devices-1;
-		if (file->f_mode & FMODE_WRITE && !s->dma[mixer.devnr].opened) {
-			/* modify only if device not open */
-			if (mixer.o_offset < 0)
-				mixer.o_offset = 0;
-			if (mixer.o_offset >= RME96xx_CHANNELS_PER_CARD)
-				mixer.o_offset = RME96xx_CHANNELS_PER_CARD-1;
-			if (mixer.i_offset < 0)
-				mixer.i_offset = 0;
-			if (mixer.i_offset >= RME96xx_CHANNELS_PER_CARD)
-				mixer.i_offset = RME96xx_CHANNELS_PER_CARD-1;
-			s->dma[mixer.devnr].outoffset = mixer.o_offset;
-			s->dma[mixer.devnr].inoffset = mixer.i_offset;
-		}
-
-		mixer.o_offset = s->dma[mixer.devnr].outoffset;
-		mixer.i_offset = s->dma[mixer.devnr].inoffset;
-
-		return copy_to_user(argp, &mixer, sizeof(mixer)) ? -EFAULT : 0;
-	}
-	if (cmd == SOUND_MIXER_PRIVATE2) {
-		return put_user(status, p);
-	}
-	if (cmd == SOUND_MIXER_PRIVATE3) {
-		u32 control;
-		if (copy_from_user(&control,argp,sizeof(control)))
-			return -EFAULT;
-		if (file->f_mode & FMODE_WRITE) {
-			s->control_register &= ~RME96xx_mixer_allowed;
-			s->control_register |= control & RME96xx_mixer_allowed;
-			writel(control,s->iobase + RME96xx_control_register);
-		}
-
-	     return put_user(s->control_register, p);
-	}
-	return -1;
-}
-
-
-
-static int rme96xx_mixer_release(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static /*const*/ struct file_operations rme96xx_mixer_fops = {
-	.owner	 = THIS_MODULE,
-	.ioctl	 = rme96xx_mixer_ioctl,
-	.open	 = rme96xx_mixer_open,
-	.release = rme96xx_mixer_release,
-};
diff --git a/sound/oss/rme96xx.h b/sound/oss/rme96xx.h
deleted file mode 100644
index 7a3c188..0000000
--- a/sound/oss/rme96xx.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* (C) 2000 Guenter Geiger <geiger@debian.org>
-   with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
-
-Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-   HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
-   HP20020201 completed?
-
-A text/graphic control panel (rmectrl/xrmectrl) is available from
-   http://gige.xdv.org/pages/soft/pages/rme
-*/
-
-
-#ifndef AFMT_S32_BLOCKED
-#define AFMT_S32_BLOCKED 0x0000400
-#endif
-
-/* AFMT_S16_BLOCKED not yet supported */
-#ifndef AFMT_S16_BLOCKED 
-#define AFMT_S16_BLOCKED 0x0000800
-#endif
-
-
-typedef struct rme_status {
-	unsigned int irq:1;
-	unsigned int lockmask:3;     /* ADAT input PLLs locked */
-	                             /*   100=ADAT1, 010=ADAT2, 001=ADAT3 */
-	unsigned int sr48:1;         /* sample rate: 0=44.1/88.2 1=48/96 kHz */
-	unsigned int wclock:1;       /* 1=wordclock used */
-	unsigned int bufpoint:10;
-	unsigned int syncmask:3;     /* ADAT input in sync with system clock */
-	                             /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
-	unsigned int doublespeed:1;  /* sample rate: 0=44.1/48 1=88.2/96 kHz */
-	unsigned int tc_busy:1;
-	unsigned int tc_out:1;
-	unsigned int crystalrate:3;  /* spdif input sample rate: */
-	                             /*   000=64kHz, 100=88.2kHz, 011=96kHz */
-	                             /*   111=32kHz, 110=44.1kHz, 101=48kHz */
-	unsigned int spdif_error:1;  /* 1=no spdif lock */
-	unsigned int bufid:1;
-	unsigned int tc_valid:1;     /* 1=timecode input detected */
-	unsigned int spdif_read:1;
-} rme_status_t;
-
-
-/* only fields marked W: can be modified by writing to SOUND_MIXER_PRIVATE3 */
-typedef struct rme_control {
-	unsigned int start:1;
-	unsigned int latency:3;      /* buffer size / latency [samples]: */
-	                             /*   0=64 ... 7=8192 */
-	unsigned int master:1;       /* W: clock mode: 1=master 0=slave/auto */
-	unsigned int ie:1;
-	unsigned int sr48:1;         /* samplerate 0=44.1/88.2, 1=48/96 kHz */
-	unsigned int spare:1;
-	unsigned int doublespeed:1;  /* double speed 0=44.1/48, 1=88.2/96 Khz */
-	unsigned int pro:1;          /* W: SPDIF-OUT 0=consumer, 1=professional */
-	unsigned int emphasis:1;     /* W: SPDIF-OUT emphasis 0=off, 1=on */
-	unsigned int dolby:1;        /* W: SPDIF-OUT non-audio bit 1=set, 0=unset */
-	unsigned int opt_out:1;      /* W: use 1st optical OUT as SPDIF: 1=yes, 0=no */
-	unsigned int wordclock:1;    /* W: use Wordclock as sync (overwrites master) */
-        unsigned int spdif_in:2;     /* W: SPDIF-IN: */
-                                     /*    00=optical (ADAT1), 01=coaxial (Cinch), 10=internal CDROM */
-	unsigned int sync_ref:2;     /* W: preferred sync-source in autosync */
-                                     /*    00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
-	unsigned int spdif_reset:1;
-	unsigned int spdif_select:1;
-	unsigned int spdif_clock:1;
-	unsigned int spdif_write:1;
-	unsigned int adat1_cd:1;     /* W: Rev 1.5+: if set, internal CD connector carries ADAT */
-} rme_ctrl_t;
-
-
-typedef struct _rme_mixer {
-	int i_offset;
-	int o_offset;
-	int devnr;
-	int spare[8];
-} rme_mixer;
-
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
index 0ce4e4e..5c215f7 100644
--- a/sound/oss/sequencer.c
+++ b/sound/oss/sequencer.c
@@ -16,7 +16,6 @@
  */
 #include <linux/kmod.h>
 #include <linux/spinlock.h>
-#define SEQUENCER_C
 #include "sound_config.h"
 
 #include "midi_ctrl.h"
@@ -157,6 +156,7 @@
 	wake_up(&midi_sleeper);
 	spin_unlock_irqrestore(&lock,flags);
 }
+EXPORT_SYMBOL(seq_copy_to_input);
 
 static void sequencer_midi_input(int dev, unsigned char data)
 {
@@ -206,6 +206,7 @@
 	}
 	seq_copy_to_input(event_rec, len);
 }
+EXPORT_SYMBOL(seq_input_event);
 
 int sequencer_write(int dev, struct file *file, const char __user *buf, int count)
 {
@@ -1554,6 +1555,7 @@
 {
 	seq_startplay();
 }
+EXPORT_SYMBOL(sequencer_timer);
 
 int note_to_freq(int note_num)
 {
@@ -1587,6 +1589,7 @@
 
 	return note_freq;
 }
+EXPORT_SYMBOL(note_to_freq);
 
 unsigned long compute_finetune(unsigned long base_freq, int bend, int range,
 		 int vibrato_cents)
@@ -1640,19 +1643,12 @@
 	else
 		return (base_freq * amount) / 10000;	/* Bend up */
 }
-
+EXPORT_SYMBOL(compute_finetune);
 
 void sequencer_init(void)
 {
-	/* drag in sequencer_syms.o */
-	{
-		extern char sequencer_syms_symbol;
-		sequencer_syms_symbol = 0;
-	}
-
 	if (sequencer_ok)
 		return;
-	MIDIbuf_init();
 	queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
 	if (queue == NULL)
 	{
@@ -1668,6 +1664,7 @@
 	}
 	sequencer_ok = 1;
 }
+EXPORT_SYMBOL(sequencer_init);
 
 void sequencer_unload(void)
 {
diff --git a/sound/oss/sequencer_syms.c b/sound/oss/sequencer_syms.c
deleted file mode 100644
index 5d00879..0000000
--- a/sound/oss/sequencer_syms.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Exported symbols for sequencer driver.
- */
-
-#include <linux/module.h>
-
-char sequencer_syms_symbol;
-
-#include "sound_config.h"
-#include "sound_calls.h"
-
-EXPORT_SYMBOL(note_to_freq);
-EXPORT_SYMBOL(compute_finetune);
-EXPORT_SYMBOL(seq_copy_to_input);
-EXPORT_SYMBOL(seq_input_event);
-EXPORT_SYMBOL(sequencer_init);
-EXPORT_SYMBOL(sequencer_timer);
-
-EXPORT_SYMBOL(sound_timer_init);
-EXPORT_SYMBOL(sound_timer_interrupt);
-EXPORT_SYMBOL(sound_timer_syncinterval);
-
-/* Tuning */
-
-#define _SEQUENCER_C_
-#include "tuning.h"
-
-EXPORT_SYMBOL(cent_tuning);
-EXPORT_SYMBOL(semitone_tuning);
diff --git a/sound/oss/sgalaxy.c b/sound/oss/sgalaxy.c
deleted file mode 100644
index 0bcff67..0000000
--- a/sound/oss/sgalaxy.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * sound/oss/sgalaxy.c
- *
- * Low level driver for Aztech Sound Galaxy cards.
- * Copyright 1998 Artur Skawina <skawina@geocities.com>
- *
- * Supported cards:
- *    Aztech Sound Galaxy Waverider Pro 32 - 3D
- *    Aztech Sound Galaxy Washington 16
- *
- * Based on cs4232.c by Hannu Savolainen and Alan Cox.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- *		Added __init to sb_rst() and sb_cmd()
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-#include "ad1848.h"
-
-static void sleep( unsigned howlong )
-{
-	current->state   = TASK_INTERRUPTIBLE;
-	schedule_timeout(howlong);
-}
-
-#define DPORT 0x80
-
-/* Sound Blaster regs */
-
-#define SBDSP_RESET      0x6
-#define SBDSP_READ       0xA
-#define SBDSP_COMMAND    0xC
-#define SBDSP_STATUS     SBDSP_COMMAND
-#define SBDSP_DATA_AVAIL 0xE
-
-static int __init sb_rst(int base)
-{
-	int   i;
-   
-	outb( 1, base+SBDSP_RESET );     /* reset the DSP */
-	outb( 0, base+SBDSP_RESET );
-    
-	for ( i=0; i<500; i++ )          /* delay */
-		inb(DPORT);
-      
-	for ( i=0; i<100000; i++ )
-	{
-		if ( inb( base+SBDSP_DATA_AVAIL )&0x80 )
-			break;
-	}
-
-	if ( inb( base+SBDSP_READ )!=0xAA )
-		return 0;
-
-	return 1;
-}
-
-static int __init sb_cmd( int base, unsigned char val )
-{
-	int  i;
-
-	for ( i=100000; i; i-- )
-	{
-		if ( (inb( base+SBDSP_STATUS )&0x80)==0 )
-		{
-        		outb( val, base+SBDSP_COMMAND );
-        		break;
-		}
-	}
-	return i;      /* i>0 == success */
-}
-
-
-#define ai_sgbase    driver_use_1
-
-static int __init probe_sgalaxy( struct address_info *ai )
-{
-	struct resource *ports;
-	int n;
-
-	if (!request_region(ai->io_base, 4, "WSS config")) {
-		printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
-		return 0;
-	}
-
-	ports = request_region(ai->io_base + 4, 4, "ad1848");
-	if (!ports) {
-		printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
-		release_region(ai->io_base, 4);
-		return 0;
-	}
-
-	if (!request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB")) {
-		printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
-		release_region(ai->io_base + 4, 4);
-		release_region(ai->io_base, 4);
-		return 0;
-	}
-        
-	if (ad1848_detect(ports, NULL, ai->osp))
-		goto out;  /* The card is already active, check irq etc... */
-        
-	/* switch to MSS/WSS mode */
-   
-	sb_rst( ai->ai_sgbase );
-   
-	sb_cmd( ai->ai_sgbase, 9 );
-	sb_cmd( ai->ai_sgbase, 0 );
-
-	sleep( HZ/10 );
-
-out:
-      	if (!probe_ms_sound(ai, ports)) {
-		release_region(ai->io_base + 4, 4);
-		release_region(ai->io_base, 4);
-		release_region(ai->ai_sgbase, 0x10);
-		return 0;
-	}
-
-	attach_ms_sound(ai, ports, THIS_MODULE);
-	n=ai->slots[0];
-	
-	if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) {
-		AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE );   /* Line-in */
-		AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH );  /* FM+Wavetable*/
-		AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD );     /* CD */
-	}
-	return 1;
-}
-
-static void __exit unload_sgalaxy( struct address_info *ai )
-{
-	unload_ms_sound( ai );
-	release_region( ai->ai_sgbase, 0x10 );
-}
-
-static struct address_info cfg;
-
-static int __initdata io	= -1;
-static int __initdata irq	= -1;
-static int __initdata dma	= -1;
-static int __initdata dma2	= -1;
-static int __initdata sgbase	= -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma2, int, 0);
-module_param(sgbase, int, 0);
-
-static int __init init_sgalaxy(void)
-{
-	cfg.io_base   = io;
-	cfg.irq       = irq;
-	cfg.dma       = dma;
-	cfg.dma2      = dma2;
-	cfg.ai_sgbase = sgbase;
-
-	if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
-		printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
-		return -EINVAL;
-	}
-
-	if ( probe_sgalaxy(&cfg) == 0 )
-		return -ENODEV;
-
-	return 0;
-}
-
-static void __exit cleanup_sgalaxy(void)
-{
-	unload_sgalaxy(&cfg);
-}
-
-module_init(init_sgalaxy);
-module_exit(cleanup_sgalaxy);
-
-#ifndef MODULE
-static int __init setup_sgalaxy(char *str)
-{
-	/* io, irq, dma, dma2, sgbase */
-	int ints[6];
-	
-	str = get_options(str, ARRAY_SIZE(ints), ints);
-	io	= ints[1];
-	irq	= ints[2];
-	dma	= ints[3];
-	dma2	= ints[4];
-	sgbase	= ints[5];
-
-	return 1;
-}
-
-__setup("sgalaxy=", setup_sgalaxy);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
deleted file mode 100644
index 8ea532d..0000000
--- a/sound/oss/sonicvibes.c
+++ /dev/null
@@ -1,2792 +0,0 @@
-/*****************************************************************************/
-
-/*
- *      sonicvibes.c  --  S3 Sonic Vibes audio driver.
- *
- *      Copyright (C) 1998-2001, 2003  Thomas Sailer (t.sailer@alumni.ethz.ch)
- *
- *      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.
- *
- * Special thanks to David C. Niemi
- *
- *
- * Module command line parameters:
- *   none so far
- *
- *
- *  Supported devices:
- *  /dev/dsp    standard /dev/dsp device, (mostly) OSS compatible
- *  /dev/mixer  standard /dev/mixer device, (mostly) OSS compatible
- *  /dev/midi   simple MIDI UART interface, no ioctl
- *
- *  The card has both an FM and a Wavetable synth, but I have to figure
- *  out first how to drive them...
- *
- *  Revision history
- *    06.05.1998   0.1   Initial release
- *    10.05.1998   0.2   Fixed many bugs, esp. ADC rate calculation
- *                       First stab at a simple midi interface (no bells&whistles)
- *    13.05.1998   0.3   Fix stupid cut&paste error: set_adc_rate was called instead of
- *                       set_dac_rate in the FMODE_WRITE case in sv_open
- *                       Fix hwptr out of bounds (now mpg123 works)
- *    14.05.1998   0.4   Don't allow excessive interrupt rates
- *    08.06.1998   0.5   First release using Alan Cox' soundcore instead of miscdevice
- *    03.08.1998   0.6   Do not include modversions.h
- *                       Now mixer behaviour can basically be selected between
- *                       "OSS documented" and "OSS actual" behaviour
- *    31.08.1998   0.7   Fix realplayer problems - dac.count issues
- *    10.12.1998   0.8   Fix drain_dac trying to wait on not yet initialized DMA
- *    16.12.1998   0.9   Fix a few f_file & FMODE_ bugs
- *    06.01.1999   0.10  remove the silly SA_INTERRUPT flag.
- *                       hopefully killed the egcs section type conflict
- *    12.03.1999   0.11  cinfo.blocks should be reset after GETxPTR ioctl.
- *                       reported by Johan Maes <joma@telindus.be>
- *    22.03.1999   0.12  return EAGAIN instead of EBUSY when O_NONBLOCK
- *                       read/write cannot be executed
- *    05.04.1999   0.13  added code to sv_read and sv_write which should detect
- *                       lockups of the sound chip and revive it. This is basically
- *                       an ugly hack, but at least applications using this driver
- *                       won't hang forever. I don't know why these lockups happen,
- *                       it might well be the motherboard chipset (an early 486 PCI
- *                       board with ALI chipset), since every busmastering 100MB
- *                       ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
- *                       exhibit similar behaviour (they work for a couple of packets
- *                       and then lock up and can be revived by ifconfig down/up).
- *    07.04.1999   0.14  implemented the following ioctl's: SOUND_PCM_READ_RATE, 
- *                       SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS; 
- *                       Alpha fixes reported by Peter Jones <pjones@redhat.com>
- *                       Note: dmaio hack might still be wrong on archs other than i386
- *    15.06.1999   0.15  Fix bad allocation bug.
- *                       Thanks to Deti Fliegl <fliegl@in.tum.de>
- *    28.06.1999   0.16  Add pci_set_master
- *    03.08.1999   0.17  adapt to Linus' new __setup/__initcall
- *                       added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
- *    12.08.1999   0.18  module_init/__setup fixes
- *    24.08.1999   0.19  get rid of the dmaio kludge, replace with allocate_resource
- *    31.08.1999   0.20  add spin_lock_init
- *                       use new resource allocation to allocate DDMA IO space
- *                       replaced current->state = x with set_current_state(x)
- *    03.09.1999   0.21  change read semantics for MIDI to match
- *                       OSS more closely; remove possible wakeup race
- *    28.10.1999   0.22  More waitqueue races fixed
- *    01.12.1999   0.23  New argument to allocate_resource
- *    07.12.1999   0.24  More allocate_resource semantics change
- *    08.01.2000   0.25  Prevent some ioctl's from returning bad count values on underrun/overrun;
- *                       Tim Janik's BSE (Bedevilled Sound Engine) found this
- *                       use Martin Mares' pci_assign_resource
- *    07.02.2000   0.26  Use pci_alloc_consistent and pci_register_driver
- *    21.11.2000   0.27  Initialize dma buffers in poll, otherwise poll may return a bogus mask
- *    12.12.2000   0.28  More dma buffer initializations, patch from
- *                       Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- *    31.01.2001   0.29  Register/Unregister gameport
- *                       Fix SETTRIGGER non OSS API conformity
- *    18.05.2001   0.30  PCI probing and error values cleaned up by Marcus
- *                       Meissner <mm@caldera.de>
- *    03.01.2003   0.31  open_mode fixes from Georg Acher <acher@in.tum.de>
- *
- */
-
-/*****************************************************************************/
-      
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/gameport.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "dm.h"
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_S3
-#define PCI_VENDOR_ID_S3             0x5333
-#endif
-#ifndef PCI_DEVICE_ID_S3_SONICVIBES
-#define PCI_DEVICE_ID_S3_SONICVIBES  0xca00
-#endif
-
-#define SV_MAGIC  ((PCI_VENDOR_ID_S3<<16)|PCI_DEVICE_ID_S3_SONICVIBES)
-
-#define SV_EXTENT_SB      0x10
-#define SV_EXTENT_ENH     0x10
-#define SV_EXTENT_SYNTH   0x4
-#define SV_EXTENT_MIDI    0x4
-#define SV_EXTENT_GAME    0x8
-#define SV_EXTENT_DMA     0x10
-
-/*
- * we are not a bridge and thus use a resource for DDMA that is used for bridges but
- * left empty for normal devices
- */
-#define RESOURCE_SB       0
-#define RESOURCE_ENH      1
-#define RESOURCE_SYNTH    2
-#define RESOURCE_MIDI     3
-#define RESOURCE_GAME     4
-#define RESOURCE_DDMA     7
-
-#define SV_MIDI_DATA      0
-#define SV_MIDI_COMMAND   1
-#define SV_MIDI_STATUS    1
-
-#define SV_DMA_ADDR0      0
-#define SV_DMA_ADDR1      1
-#define SV_DMA_ADDR2      2
-#define SV_DMA_ADDR3      3
-#define SV_DMA_COUNT0     4
-#define SV_DMA_COUNT1     5
-#define SV_DMA_COUNT2     6
-#define SV_DMA_MODE       0xb
-#define SV_DMA_RESET      0xd
-#define SV_DMA_MASK       0xf
-
-/*
- * DONT reset the DMA controllers unless you understand
- * the reset semantics. Assuming reset semantics as in
- * the 8237 does not work.
- */
-
-#define DMA_MODE_AUTOINIT 0x10
-#define DMA_MODE_READ     0x44    /* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE    0x48    /* memory to I/O, no autoinit, increment, single mode */
-
-#define SV_CODEC_CONTROL  0
-#define SV_CODEC_INTMASK  1
-#define SV_CODEC_STATUS   2
-#define SV_CODEC_IADDR    4
-#define SV_CODEC_IDATA    5
-
-#define SV_CCTRL_RESET      0x80
-#define SV_CCTRL_INTADRIVE  0x20
-#define SV_CCTRL_WAVETABLE  0x08
-#define SV_CCTRL_REVERB     0x04
-#define SV_CCTRL_ENHANCED   0x01
-
-#define SV_CINTMASK_DMAA    0x01
-#define SV_CINTMASK_DMAC    0x04
-#define SV_CINTMASK_SPECIAL 0x08
-#define SV_CINTMASK_UPDOWN  0x40
-#define SV_CINTMASK_MIDI    0x80
-
-#define SV_CSTAT_DMAA       0x01
-#define SV_CSTAT_DMAC	    0x04
-#define SV_CSTAT_SPECIAL    0x08
-#define SV_CSTAT_UPDOWN	    0x40
-#define SV_CSTAT_MIDI	    0x80
-
-#define SV_CIADDR_TRD       0x80
-#define SV_CIADDR_MCE       0x40
-
-/* codec indirect registers */
-#define SV_CIMIX_ADCINL     0x00
-#define SV_CIMIX_ADCINR     0x01
-#define SV_CIMIX_AUX1INL    0x02
-#define SV_CIMIX_AUX1INR    0x03
-#define SV_CIMIX_CDINL      0x04
-#define SV_CIMIX_CDINR      0x05
-#define SV_CIMIX_LINEINL    0x06
-#define SV_CIMIX_LINEINR    0x07
-#define SV_CIMIX_MICIN      0x08
-#define SV_CIMIX_SYNTHINL   0x0A
-#define SV_CIMIX_SYNTHINR   0x0B
-#define SV_CIMIX_AUX2INL    0x0C
-#define SV_CIMIX_AUX2INR    0x0D
-#define SV_CIMIX_ANALOGINL  0x0E
-#define SV_CIMIX_ANALOGINR  0x0F
-#define SV_CIMIX_PCMINL     0x10
-#define SV_CIMIX_PCMINR     0x11
-
-#define SV_CIGAMECONTROL    0x09
-#define SV_CIDATAFMT        0x12
-#define SV_CIENABLE         0x13
-#define SV_CIUPDOWN         0x14
-#define SV_CIREVISION       0x15
-#define SV_CIADCOUTPUT      0x16
-#define SV_CIDMAABASECOUNT1 0x18
-#define SV_CIDMAABASECOUNT0 0x19
-#define SV_CIDMACBASECOUNT1 0x1c
-#define SV_CIDMACBASECOUNT0 0x1d
-#define SV_CIPCMSR0         0x1e
-#define SV_CIPCMSR1         0x1f
-#define SV_CISYNTHSR0       0x20
-#define SV_CISYNTHSR1       0x21
-#define SV_CIADCCLKSOURCE   0x22
-#define SV_CIADCALTSR       0x23
-#define SV_CIADCPLLM        0x24
-#define SV_CIADCPLLN        0x25
-#define SV_CISYNTHPLLM      0x26
-#define SV_CISYNTHPLLN      0x27
-#define SV_CIUARTCONTROL    0x2a
-#define SV_CIDRIVECONTROL   0x2b
-#define SV_CISRSSPACE       0x2c
-#define SV_CISRSCENTER      0x2d
-#define SV_CIWAVETABLESRC   0x2e
-#define SV_CIANALOGPWRDOWN  0x30
-#define SV_CIDIGITALPWRDOWN 0x31
-
-
-#define SV_CIMIX_ADCSRC_CD     0x20
-#define SV_CIMIX_ADCSRC_DAC    0x40
-#define SV_CIMIX_ADCSRC_AUX2   0x60
-#define SV_CIMIX_ADCSRC_LINE   0x80
-#define SV_CIMIX_ADCSRC_AUX1   0xa0
-#define SV_CIMIX_ADCSRC_MIC    0xc0
-#define SV_CIMIX_ADCSRC_MIXOUT 0xe0
-#define SV_CIMIX_ADCSRC_MASK   0xe0
-
-#define SV_CFMT_STEREO     0x01
-#define SV_CFMT_16BIT      0x02
-#define SV_CFMT_MASK       0x03
-#define SV_CFMT_ASHIFT     0   
-#define SV_CFMT_CSHIFT     4
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-#define SV_CENABLE_PPE     0x4
-#define SV_CENABLE_RE      0x2
-#define SV_CENABLE_PE      0x1
-
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF  256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 2
-#define FMODE_MIDI_READ  (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define FMODE_DMFM 0x10
-
-/* --------------------------------------------------------------------- */
-
-struct sv_state {
-	/* magic */
-	unsigned int magic;
-
-	/* list of sonicvibes devices */
-	struct list_head devs;
-
-	/* the corresponding pci_dev structure */
-	struct pci_dev *dev;
-
-	/* soundcore stuff */
-	int dev_audio;
-	int dev_mixer;
-	int dev_midi;
-	int dev_dmfm;
-
-	/* hardware resources */
-	unsigned long iosb, ioenh, iosynth, iomidi;  /* long for SPARC */
-	unsigned int iodmaa, iodmac, irq;
-
-        /* mixer stuff */
-        struct {
-                unsigned int modcnt;
-#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS
-		unsigned short vol[13];
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-        } mix;
-
-	/* wave stuff */
-	unsigned int rateadc, ratedac;
-	unsigned char fmt, enable;
-
-	spinlock_t lock;
-	struct mutex open_mutex;
-	mode_t open_mode;
-	wait_queue_head_t open_wait;
-
-	struct dmabuf {
-		void *rawbuf;
-		dma_addr_t dmaaddr;
-		unsigned buforder;
-		unsigned numfrag;
-		unsigned fragshift;
-		unsigned hwptr, swptr;
-		unsigned total_bytes;
-		int count;
-		unsigned error; /* over/underrun */
-		wait_queue_head_t wait;
-		/* redundant, but makes calculations easier */
-		unsigned fragsize;
-		unsigned dmasize;
-		unsigned fragsamples;
-		/* OSS stuff */
-		unsigned mapped:1;
-		unsigned ready:1;
-		unsigned endcleared:1;
-		unsigned enabled:1;
-		unsigned ossfragshift;
-		int ossmaxfrags;
-		unsigned subdivision;
-	} dma_dac, dma_adc;
-
-	/* midi stuff */
-	struct {
-		unsigned ird, iwr, icnt;
-		unsigned ord, owr, ocnt;
-		wait_queue_head_t iwait;
-		wait_queue_head_t owait;
-		struct timer_list timer;
-		unsigned char ibuf[MIDIINBUF];
-		unsigned char obuf[MIDIOUTBUF];
-	} midi;
-
-#if SUPPORT_JOYSTICK
-	struct gameport *gameport;
-#endif
-};
-
-/* --------------------------------------------------------------------- */
-
-static LIST_HEAD(devs);
-static unsigned long wavetable_mem;
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
-	unsigned r = 0;
-	
-	if (x >= 0x10000) {
-		x >>= 16;
-		r += 16;
-	}
-	if (x >= 0x100) {
-		x >>= 8;
-		r += 8;
-	}
-	if (x >= 0x10) {
-		x >>= 4;
-		r += 4;
-	}
-	if (x >= 4) {
-		x >>= 2;
-		r += 2;
-	}
-	if (x >= 2)
-		r++;
-	return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver.
- */
-
-#undef DMABYTEIO
-
-static void set_dmaa(struct sv_state *s, unsigned int addr, unsigned int count)
-{
-#ifdef DMABYTEIO
-	unsigned io = s->iodmaa, u;
-
-	count--;
-	for (u = 4; u > 0; u--, addr >>= 8, io++)
-		outb(addr & 0xff, io);
-	for (u = 3; u > 0; u--, count >>= 8, io++)
-		outb(count & 0xff, io);
-#else /* DMABYTEIO */
-	count--;
-	outl(addr, s->iodmaa + SV_DMA_ADDR0);
-	outl(count, s->iodmaa + SV_DMA_COUNT0);
-#endif /* DMABYTEIO */
-	outb(0x18, s->iodmaa + SV_DMA_MODE);
-}
-
-static void set_dmac(struct sv_state *s, unsigned int addr, unsigned int count)
-{
-#ifdef DMABYTEIO
-	unsigned io = s->iodmac, u;
-
-	count >>= 1;
-	count--;
-	for (u = 4; u > 0; u--, addr >>= 8, io++)
-		outb(addr & 0xff, io);
-	for (u = 3; u > 0; u--, count >>= 8, io++)
-		outb(count & 0xff, io);
-#else /* DMABYTEIO */
-	count >>= 1;
-	count--;
-	outl(addr, s->iodmac + SV_DMA_ADDR0);
-	outl(count, s->iodmac + SV_DMA_COUNT0);
-#endif /* DMABYTEIO */
-	outb(0x14, s->iodmac + SV_DMA_MODE);
-}
-
-static inline unsigned get_dmaa(struct sv_state *s)
-{
-#ifdef DMABYTEIO
-	unsigned io = s->iodmaa+6, v = 0, u;
-
-	for (u = 3; u > 0; u--, io--) {
-		v <<= 8;
-		v |= inb(io);
-	}
-	return v + 1;
-#else /* DMABYTEIO */
-	return (inl(s->iodmaa + SV_DMA_COUNT0) & 0xffffff) + 1;
-#endif /* DMABYTEIO */
-}
-
-static inline unsigned get_dmac(struct sv_state *s)
-{
-#ifdef DMABYTEIO
-	unsigned io = s->iodmac+6, v = 0, u;
-
-	for (u = 3; u > 0; u--, io--) {
-		v <<= 8;
-		v |= inb(io);
-	}
-	return (v + 1) << 1;
-#else /* DMABYTEIO */
-	return ((inl(s->iodmac + SV_DMA_COUNT0) & 0xffffff) + 1) << 1;
-#endif /* DMABYTEIO */
-}
-
-static void wrindir(struct sv_state *s, unsigned char idx, unsigned char data)
-{
-	outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
-	udelay(10);
-	outb(data, s->ioenh + SV_CODEC_IDATA);
-	udelay(10);
-}
-
-static unsigned char rdindir(struct sv_state *s, unsigned char idx)
-{
-	unsigned char v;
-
-	outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
-	udelay(10);
-	v = inb(s->ioenh + SV_CODEC_IDATA);
-	udelay(10);
-	return v;
-}
-
-static void set_fmt(struct sv_state *s, unsigned char mask, unsigned char data)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	outb(SV_CIDATAFMT | SV_CIADDR_MCE, s->ioenh + SV_CODEC_IADDR);
-	if (mask) {
-		s->fmt = inb(s->ioenh + SV_CODEC_IDATA);
-		udelay(10);
-	}
-	s->fmt = (s->fmt & mask) | data;
-	outb(s->fmt, s->ioenh + SV_CODEC_IDATA);
-	udelay(10);
-	outb(0, s->ioenh + SV_CODEC_IADDR);
-	spin_unlock_irqrestore(&s->lock, flags);
-	udelay(10);
-}
-
-static void frobindir(struct sv_state *s, unsigned char idx, unsigned char mask, unsigned char data)
-{
-	outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
-	udelay(10);
-	outb((inb(s->ioenh + SV_CODEC_IDATA) & mask) ^ data, s->ioenh + SV_CODEC_IDATA);
-	udelay(10);
-}
-
-#define REFFREQUENCY  24576000
-#define ADCMULT 512
-#define FULLRATE 48000
-
-static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate)
-{
-	unsigned long flags;
-	unsigned char r, m=0, n=0;
-	unsigned xm, xn, xr, xd, metric = ~0U;
-	/* the warnings about m and n used uninitialized are bogus and may safely be ignored */
-
-	if (rate < 625000/ADCMULT)
-		rate = 625000/ADCMULT;
-	if (rate > 150000000/ADCMULT)
-		rate = 150000000/ADCMULT;
-	/* slight violation of specs, needed for continuous sampling rates */
-	for (r = 0; rate < 75000000/ADCMULT; r += 0x20, rate <<= 1);
-	for (xn = 3; xn < 35; xn++)
-		for (xm = 3; xm < 130; xm++) {
-			xr = REFFREQUENCY/ADCMULT * xm / xn;
-			xd = abs((signed)(xr - rate));
-			if (xd < metric) {
-				metric = xd;
-				m = xm - 2;
-				n = xn - 2;
-			}
-		}
-	reg &= 0x3f;
-	spin_lock_irqsave(&s->lock, flags);
-	outb(reg, s->ioenh + SV_CODEC_IADDR);
-	udelay(10);
-	outb(m, s->ioenh + SV_CODEC_IDATA);
-	udelay(10);
-	outb(reg+1, s->ioenh + SV_CODEC_IADDR);
-	udelay(10);
-	outb(r | n, s->ioenh + SV_CODEC_IDATA);
-	spin_unlock_irqrestore(&s->lock, flags);
-	udelay(10);
-	return (REFFREQUENCY/ADCMULT * (m + 2) / (n + 2)) >> ((r >> 5) & 7);
-}
-
-#if 0
-
-static unsigned getpll(struct sv_state *s, unsigned char reg)
-{
-	unsigned long flags;
-	unsigned char m, n;
-
-	reg &= 0x3f;
-	spin_lock_irqsave(&s->lock, flags);
-	outb(reg, s->ioenh + SV_CODEC_IADDR);
-	udelay(10);
-	m = inb(s->ioenh + SV_CODEC_IDATA);
-	udelay(10);
-	outb(reg+1, s->ioenh + SV_CODEC_IADDR);
-	udelay(10);
-	n = inb(s->ioenh + SV_CODEC_IDATA);
-	spin_unlock_irqrestore(&s->lock, flags);
-	udelay(10);
-	return (REFFREQUENCY/ADCMULT * (m + 2) / ((n & 0x1f) + 2)) >> ((n >> 5) & 7);
-}
-
-#endif
-
-static void set_dac_rate(struct sv_state *s, unsigned rate)
-{
-	unsigned div;
-	unsigned long flags;
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 4000)
-		rate = 4000;
-	div = (rate * 65536 + FULLRATE/2) / FULLRATE;
-	if (div > 65535)
-		div = 65535;
-	spin_lock_irqsave(&s->lock, flags);
-	wrindir(s, SV_CIPCMSR1, div >> 8);
-	wrindir(s, SV_CIPCMSR0, div);
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->ratedac = (div * FULLRATE + 32768) / 65536;
-}
-
-static void set_adc_rate(struct sv_state *s, unsigned rate)
-{
-	unsigned long flags;
-	unsigned rate1, rate2, div;
-
-	if (rate > 48000)
-		rate = 48000;
-	if (rate < 4000)
-		rate = 4000;
-	rate1 = setpll(s, SV_CIADCPLLM, rate);
-	div = (48000 + rate/2) / rate;
-	if (div > 8)
-		div = 8;
-	rate2 = (48000 + div/2) / div;
-	spin_lock_irqsave(&s->lock, flags);
-	wrindir(s, SV_CIADCALTSR, (div-1) << 4);
-	if (abs((signed)(rate-rate2)) <= abs((signed)(rate-rate1))) {
-		wrindir(s, SV_CIADCCLKSOURCE, 0x10);
-		s->rateadc = rate2;
-	} else {
-		wrindir(s, SV_CIADCCLKSOURCE, 0x00);
-		s->rateadc = rate1;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct sv_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->enable &= ~SV_CENABLE_RE;
-	wrindir(s, SV_CIENABLE, s->enable);
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static inline void stop_dac(struct sv_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	s->enable &= ~(SV_CENABLE_PPE | SV_CENABLE_PE);
-	wrindir(s, SV_CIENABLE, s->enable);
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static void start_dac(struct sv_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
-		s->enable = (s->enable & ~SV_CENABLE_PPE) | SV_CENABLE_PE;
-		wrindir(s, SV_CIENABLE, s->enable);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-static void start_adc(struct sv_state *s)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize)) 
-	    && s->dma_adc.ready) {
-		s->enable |= SV_CENABLE_RE;
-		wrindir(s, SV_CIENABLE, s->enable);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-}	
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static void dealloc_dmabuf(struct sv_state *s, struct dmabuf *db)
-{
-	struct page *page, *pend;
-
-	if (db->rawbuf) {
-		/* undo marking the pages as reserved */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			ClearPageReserved(page);
-		pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
-	}
-	db->rawbuf = NULL;
-	db->mapped = db->ready = 0;
-}
-
-
-/* DMAA is used for playback, DMAC is used for recording */
-
-static int prog_dmabuf(struct sv_state *s, unsigned rec)
-{
-	struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
-	unsigned rate = rec ? s->rateadc : s->ratedac;
-	int order;
-	unsigned bytepersec;
-	unsigned bufs;
-	struct page *page, *pend;
-	unsigned char fmt;
-	unsigned long flags;
-
-	spin_lock_irqsave(&s->lock, flags);
-	fmt = s->fmt;
-	if (rec) {
-		s->enable &= ~SV_CENABLE_RE;
-		fmt >>= SV_CFMT_CSHIFT;
-	} else {
-		s->enable &= ~SV_CENABLE_PE;
-		fmt >>= SV_CFMT_ASHIFT;
-	}
-	wrindir(s, SV_CIENABLE, s->enable);
-	spin_unlock_irqrestore(&s->lock, flags);
-	fmt &= SV_CFMT_MASK;
-	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-	if (!db->rawbuf) {
-		db->ready = db->mapped = 0;
-		for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
-			if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
-				break;
-		if (!db->rawbuf)
-			return -ENOMEM;
-		db->buforder = order;
-		if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
-			printk(KERN_DEBUG "sv: DMA buffer crosses 64k boundary: busaddr 0x%lx  size %ld\n", 
-			       virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
-		if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
-			printk(KERN_DEBUG "sv: DMA buffer beyond 16MB: busaddr 0x%lx  size %ld\n", 
-			       virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
-		/* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-		pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
-		for (page = virt_to_page(db->rawbuf); page <= pend; page++)
-			SetPageReserved(page);
-	}
-	bytepersec = rate << sample_shift[fmt];
-	bufs = PAGE_SIZE << db->buforder;
-	if (db->ossfragshift) {
-		if ((1000 << db->ossfragshift) < bytepersec)
-			db->fragshift = ld2(bytepersec/1000);
-		else
-			db->fragshift = db->ossfragshift;
-	} else {
-		db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
-		if (db->fragshift < 3)
-			db->fragshift = 3;
-	}
-	db->numfrag = bufs >> db->fragshift;
-	while (db->numfrag < 4 && db->fragshift > 3) {
-		db->fragshift--;
-		db->numfrag = bufs >> db->fragshift;
-	}
-	db->fragsize = 1 << db->fragshift;
-	if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
-		db->numfrag = db->ossmaxfrags;
-	db->fragsamples = db->fragsize >> sample_shift[fmt];
-	db->dmasize = db->numfrag << db->fragshift;
-	memset(db->rawbuf, (fmt & SV_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
-	spin_lock_irqsave(&s->lock, flags);
-	if (rec) {
-		set_dmac(s, db->dmaaddr, db->numfrag << db->fragshift);
-		/* program enhanced mode registers */
-		wrindir(s, SV_CIDMACBASECOUNT1, (db->fragsamples-1) >> 8);
-		wrindir(s, SV_CIDMACBASECOUNT0, db->fragsamples-1);
-	} else {
-		set_dmaa(s, db->dmaaddr, db->numfrag << db->fragshift);
-		/* program enhanced mode registers */
-		wrindir(s, SV_CIDMAABASECOUNT1, (db->fragsamples-1) >> 8);
-		wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1);
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	db->enabled = 1;
-	db->ready = 1;
-	return 0;
-}
-
-static inline void clear_advance(struct sv_state *s)
-{
-	unsigned char c = (s->fmt & (SV_CFMT_16BIT << SV_CFMT_ASHIFT)) ? 0 : 0x80;
-	unsigned char *buf = s->dma_dac.rawbuf;
-	unsigned bsize = s->dma_dac.dmasize;
-	unsigned bptr = s->dma_dac.swptr;
-	unsigned len = s->dma_dac.fragsize;
-
-	if (bptr + len > bsize) {
-		unsigned x = bsize - bptr;
-		memset(buf + bptr, c, x);
-		bptr = 0;
-		len -= x;
-	}
-	memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void sv_update_ptr(struct sv_state *s)
-{
-	unsigned hwptr;
-	int diff;
-
-	/* update ADC pointer */
-	if (s->dma_adc.ready) {
-		hwptr = (s->dma_adc.dmasize - get_dmac(s)) % s->dma_adc.dmasize;
-		diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
-		s->dma_adc.hwptr = hwptr;
-		s->dma_adc.total_bytes += diff;
-		s->dma_adc.count += diff;
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
-			wake_up(&s->dma_adc.wait);
-		if (!s->dma_adc.mapped) {
-			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
-				s->enable &= ~SV_CENABLE_RE;
-				wrindir(s, SV_CIENABLE, s->enable);
-				s->dma_adc.error++;
-			}
-		}
-	}
-	/* update DAC pointer */
-	if (s->dma_dac.ready) {
-		hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize;
-		diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-		s->dma_dac.hwptr = hwptr;
-		s->dma_dac.total_bytes += diff;
-		if (s->dma_dac.mapped) {
-			s->dma_dac.count += diff;
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
-				wake_up(&s->dma_dac.wait);
-		} else {
-			s->dma_dac.count -= diff;
-			if (s->dma_dac.count <= 0) {
-				s->enable &= ~SV_CENABLE_PE;
-				wrindir(s, SV_CIENABLE, s->enable);
-				s->dma_dac.error++;
-			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
-				clear_advance(s);
-				s->dma_dac.endcleared = 1;
-			}
-			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
-				wake_up(&s->dma_dac.wait);
-		}
-	}
-}
-
-/* hold spinlock for the following! */
-static void sv_handle_midi(struct sv_state *s)
-{
-	unsigned char ch;
-	int wake;
-
-	wake = 0;
-	while (!(inb(s->iomidi+1) & 0x80)) {
-		ch = inb(s->iomidi);
-		if (s->midi.icnt < MIDIINBUF) {
-			s->midi.ibuf[s->midi.iwr] = ch;
-			s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
-			s->midi.icnt++;
-		}
-		wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.iwait);
-	wake = 0;
-	while (!(inb(s->iomidi+1) & 0x40) && s->midi.ocnt > 0) {
-		outb(s->midi.obuf[s->midi.ord], s->iomidi);
-		s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
-		s->midi.ocnt--;
-		if (s->midi.ocnt < MIDIOUTBUF-16)
-			wake = 1;
-	}
-	if (wake)
-		wake_up(&s->midi.owait);
-}
-
-static irqreturn_t sv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-        struct sv_state *s = (struct sv_state *)dev_id;
-	unsigned int intsrc;
-	
-	/* fastpath out, to ease interrupt sharing */
-	intsrc = inb(s->ioenh + SV_CODEC_STATUS);
-	if (!(intsrc & (SV_CSTAT_DMAA | SV_CSTAT_DMAC | SV_CSTAT_MIDI)))
-		return IRQ_NONE;
-	spin_lock(&s->lock);
-	sv_update_ptr(s);
-	sv_handle_midi(s);
-	spin_unlock(&s->lock);
-	return IRQ_HANDLED;
-}
-
-static void sv_midi_timer(unsigned long data)
-{
-	struct sv_state *s = (struct sv_state *)data;
-	unsigned long flags;
-	
-	spin_lock_irqsave(&s->lock, flags);
-	sv_handle_midi(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->midi.timer.expires = jiffies+1;
-	add_timer(&s->midi.timer);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "sv: invalid magic value\n";
-
-#define VALIDATE_STATE(s)                         \
-({                                                \
-	if (!(s) || (s)->magic != SV_MAGIC) { \
-		printk(invalid_magic);            \
-		return -ENXIO;                    \
-	}                                         \
-})
-
-/* --------------------------------------------------------------------- */
-
-#define MT_4          1
-#define MT_5MUTE      2
-#define MT_4MUTEMONO  3
-#define MT_6MUTE      4
-
-static const struct {
-	unsigned left:5;
-	unsigned right:5;
-	unsigned type:3;
-	unsigned rec:3;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
-	[SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL,    SV_CIMIX_ADCINR,    MT_4,         0 },
-	[SOUND_MIXER_LINE1]  = { SV_CIMIX_AUX1INL,   SV_CIMIX_AUX1INR,   MT_5MUTE,     5 },
-	[SOUND_MIXER_CD]     = { SV_CIMIX_CDINL,     SV_CIMIX_CDINR,     MT_5MUTE,     1 },
-	[SOUND_MIXER_LINE]   = { SV_CIMIX_LINEINL,   SV_CIMIX_LINEINR,   MT_5MUTE,     4 },
-	[SOUND_MIXER_MIC]    = { SV_CIMIX_MICIN,     SV_CIMIX_ADCINL,    MT_4MUTEMONO, 6 },
-	[SOUND_MIXER_SYNTH]  = { SV_CIMIX_SYNTHINL,  SV_CIMIX_SYNTHINR,  MT_5MUTE,     2 },
-	[SOUND_MIXER_LINE2]  = { SV_CIMIX_AUX2INL,   SV_CIMIX_AUX2INR,   MT_5MUTE,     3 },
-	[SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE,     7 },
-	[SOUND_MIXER_PCM]    = { SV_CIMIX_PCMINL,    SV_CIMIX_PCMINR,    MT_6MUTE,     0 }
-};
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-static int return_mixval(struct sv_state *s, unsigned i, int *arg)
-{
-	unsigned long flags;
-	unsigned char l, r, rl, rr;
-
-	spin_lock_irqsave(&s->lock, flags);
-	l = rdindir(s, mixtable[i].left);
-	r = rdindir(s, mixtable[i].right);
-	spin_unlock_irqrestore(&s->lock, flags);
-	switch (mixtable[i].type) {
-	case MT_4:
-		r &= 0xf;
-		l &= 0xf;
-		rl = 10 + 6 * (l & 15);
-		rr = 10 + 6 * (r & 15);
-		break;
-
-	case MT_4MUTEMONO:
-		rl = 55 - 3 * (l & 15);
-		if (r & 0x10)
-			rl += 45;
-		rr = rl;
-		r = l;
-		break;
-
-	case MT_5MUTE:
-	default:
-		rl = 100 - 3 * (l & 31);
-		rr = 100 - 3 * (r & 31);
-		break;
-				
-	case MT_6MUTE:
-		rl = 100 - 3 * (l & 63) / 2;
-		rr = 100 - 3 * (r & 63) / 2;
-		break;
-	}
-	if (l & 0x80)
-		rl = 0;
-	if (r & 0x80)
-		rr = 0;
-	return put_user((rr << 8) | rl, arg);
-}
-
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = 
-{
-	[SOUND_MIXER_RECLEV] = 1,
-	[SOUND_MIXER_LINE1]  = 2,
-	[SOUND_MIXER_CD]     = 3,
-	[SOUND_MIXER_LINE]   = 4,
-	[SOUND_MIXER_MIC]    = 5,
-	[SOUND_MIXER_SYNTH]  = 6,
-	[SOUND_MIXER_LINE2]  = 7,
-	[SOUND_MIXER_VOLUME] = 8,
-	[SOUND_MIXER_PCM]    = 9
-};
-
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static unsigned mixer_recmask(struct sv_state *s)
-{
-	unsigned long flags;
-	int i, j;
-
-	spin_lock_irqsave(&s->lock, flags);
-	j = rdindir(s, SV_CIMIX_ADCINL) >> 5;
-	spin_unlock_irqrestore(&s->lock, flags);
-	j &= 7;
-	for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++);
-	return 1 << i;
-}
-
-static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
-{
-	unsigned long flags;
-	int i, val;
-	unsigned char l, r, rl, rr;
-	int __user *p = (int __user *)arg;
-
-	VALIDATE_STATE(s);
-        if (cmd == SOUND_MIXER_INFO) {
-		mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, "SonicVibes", sizeof(info.id));
-		strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
-		info.modify_counter = s->mix.modcnt;
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == SOUND_OLD_MIXER_INFO) {
-		_old_mixer_info info;
-		memset(&info, 0, sizeof(info));
-		strlcpy(info.id, "SonicVibes", sizeof(info.id));
-		strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
-		if (copy_to_user((void __user *)arg, &info, sizeof(info)))
-			return -EFAULT;
-		return 0;
-	}
-	if (cmd == OSS_GETVERSION)
-		return put_user(SOUND_VERSION, p);
-	if (cmd == SOUND_MIXER_PRIVATE1) {  /* SRS settings */
-		if (get_user(val, p))
-			return -EFAULT;
-		spin_lock_irqsave(&s->lock, flags);
-		if (val & 1) {
-			if (val & 2) {
-				l = 4 - ((val >> 2) & 7);
-				if (l & ~3)
-					l = 4;
-				r = 4 - ((val >> 5) & 7);
-				if (r & ~3)
-					r = 4;
-				wrindir(s, SV_CISRSSPACE, l);
-				wrindir(s, SV_CISRSCENTER, r);
-			} else
-				wrindir(s, SV_CISRSSPACE, 0x80);
-		}
-		l = rdindir(s, SV_CISRSSPACE);
-		r = rdindir(s, SV_CISRSCENTER);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (l & 0x80)
-			return put_user(0, p);
-		return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, p);
-	}
-	if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
-                return -EINVAL;
-        if (_SIOC_DIR(cmd) == _SIOC_READ) {
-                switch (_IOC_NR(cmd)) {
-                case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-			return put_user(mixer_recmask(s), p);
-			
-                case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].type)
-					val |= 1 << i;
-			return put_user(val, p);
-
-                case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].rec)
-					val |= 1 << i;
-			return put_user(val, p);
-			
-                case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
-			for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
-				if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
-					val |= 1 << i;
-			return put_user(val, p);
-			
-                case SOUND_MIXER_CAPS:
-			return put_user(SOUND_CAP_EXCL_INPUT, p);
-
-		default:
-			i = _IOC_NR(cmd);
-                        if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
-                                return -EINVAL;
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-			return return_mixval(s, i, p);
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-			if (!volidx[i])
-				return -EINVAL;
-			return put_user(s->mix.vol[volidx[i]-1], p);
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-		}
-	}
-        if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE)) 
-		return -EINVAL;
-	s->mix.modcnt++;
-	switch (_IOC_NR(cmd)) {
-	case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-		if (get_user(val, p))
-			return -EFAULT;
-		i = hweight32(val);
-		if (i == 0)
-			return 0; /*val = mixer_recmask(s);*/
-		else if (i > 1) 
-			val &= ~mixer_recmask(s);
-		for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
-			if (!(val & (1 << i)))
-				continue;
-			if (mixtable[i].rec)
-				break;
-		}
-		if (i == SOUND_MIXER_NRDEVICES)
-			return 0;
-		spin_lock_irqsave(&s->lock, flags);
-		frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5);
-		frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5);
-		spin_unlock_irqrestore(&s->lock, flags);
-		return 0;
-
-	default:
-		i = _IOC_NR(cmd);
-		if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
-			return -EINVAL;
-		if (get_user(val, p))
-			return -EFAULT;
-		l = val & 0xff;
-		r = (val >> 8) & 0xff;
-		if (mixtable[i].type == MT_4MUTEMONO)
-			l = (r + l) / 2;
-		if (l > 100)
-			l = 100;
-		if (r > 100)
-			r = 100;
-		spin_lock_irqsave(&s->lock, flags);
-		switch (mixtable[i].type) {
-		case MT_4:
-			if (l >= 10)
-				l -= 10;
-			if (r >= 10)
-				r -= 10;
-			frobindir(s, mixtable[i].left, 0xf0, l / 6);
-			frobindir(s, mixtable[i].right, 0xf0, l / 6);
-			break;
-
-		case MT_4MUTEMONO:
-			rr = 0;
-			if (l < 10)
-				rl = 0x80;
-			else {
-				if (l >= 55) {
-					rr = 0x10;
-					l -= 45;
-				}
-				rl = (55 - l) / 3;
-			}
-			wrindir(s, mixtable[i].left, rl);
-			frobindir(s, mixtable[i].right, ~0x10, rr);
-			break;
-			
-		case MT_5MUTE:
-			if (l < 7)
-				rl = 0x80;
-			else
-				rl = (100 - l) / 3;
-			if (r < 7)
-				rr = 0x80;
-			else
-				rr = (100 - r) / 3;
-			wrindir(s, mixtable[i].left, rl);
-			wrindir(s, mixtable[i].right, rr);
-			break;
-				
-		case MT_6MUTE:
-			if (l < 6)
-				rl = 0x80;
-			else
-				rl = (100 - l) * 2 / 3;
-			if (r < 6)
-				rr = 0x80;
-			else
-				rr = (100 - r) * 2 / 3;
-			wrindir(s, mixtable[i].left, rl);
-			wrindir(s, mixtable[i].right, rr);
-			break;
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-                return return_mixval(s, i, p);
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-		if (!volidx[i])
-			return -EINVAL;
-		s->mix.vol[volidx[i]-1] = val;
-		return put_user(s->mix.vol[volidx[i]-1], p);
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-	}
-}
-
-/* --------------------------------------------------------------------- */
-
-static int sv_open_mixdev(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	struct list_head *list;
-	struct sv_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct sv_state, devs);
-		if (s->dev_mixer == minor)
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	return nonseekable_open(inode, file);
-}
-
-static int sv_release_mixdev(struct inode *inode, struct file *file)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	
-	VALIDATE_STATE(s);
-	return 0;
-}
-
-static int sv_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	return mixer_ioctl((struct sv_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations sv_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= sv_ioctl_mixdev,
-	.open		= sv_open_mixdev,
-	.release	= sv_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct sv_state *s, int nonblock)
-{
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	int count, tmo;
-
-	if (s->dma_dac.mapped || !s->dma_dac.ready)
-		return 0;
-        add_wait_queue(&s->dma_dac.wait, &wait);
-        for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
-                spin_lock_irqsave(&s->lock, flags);
-		count = s->dma_dac.count;
-                spin_unlock_irqrestore(&s->lock, flags);
-		if (count <= 0)
-			break;
-		if (signal_pending(current))
-                        break;
-                if (nonblock) {
-                        remove_wait_queue(&s->dma_dac.wait, &wait);
-                        set_current_state(TASK_RUNNING);
-                        return -EBUSY;
-                }
-		tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
-		tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
-		if (!schedule_timeout(tmo + 1))
-			printk(KERN_DEBUG "sv: dma timed out??\n");
-        }
-        remove_wait_queue(&s->dma_dac.wait, &wait);
-        set_current_state(TASK_RUNNING);
-        if (signal_pending(current))
-                return -ERESTARTSYS;
-        return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t sv_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_adc.mapped)
-		return -ENXIO;
-	if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
-		return ret;
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	ret = 0;
-#if 0
-	spin_lock_irqsave(&s->lock, flags);
-	sv_update_ptr(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-#endif
-        add_wait_queue(&s->dma_adc.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		swptr = s->dma_adc.swptr;
-		cnt = s->dma_adc.dmasize-swptr;
-		if (s->dma_adc.count < cnt)
-			cnt = s->dma_adc.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (s->dma_adc.enabled)
-				start_adc(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			if (!schedule_timeout(HZ)) {
-				printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count, 
-				       s->dma_adc.hwptr, s->dma_adc.swptr);
-				stop_adc(s);
-				spin_lock_irqsave(&s->lock, flags);
-				set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
-				/* program enhanced mode registers */
-				wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
-				wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1);
-				s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		swptr = (swptr + cnt) % s->dma_adc.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_adc.swptr = swptr;
-		s->dma_adc.count -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_adc.enabled)
-			start_adc(s);
-	}
-        remove_wait_queue(&s->dma_adc.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-static ssize_t sv_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned swptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (s->dma_dac.mapped)
-		return -ENXIO;
-	if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-		return ret;
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	ret = 0;
-#if 0
-	spin_lock_irqsave(&s->lock, flags);
-	sv_update_ptr(s);
-	spin_unlock_irqrestore(&s->lock, flags);
-#endif
-        add_wait_queue(&s->dma_dac.wait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		if (s->dma_dac.count < 0) {
-			s->dma_dac.count = 0;
-			s->dma_dac.swptr = s->dma_dac.hwptr;
-		}
-		swptr = s->dma_dac.swptr;
-		cnt = s->dma_dac.dmasize-swptr;
-		if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
-			cnt = s->dma_dac.dmasize - s->dma_dac.count;
-		if (cnt <= 0)
-			__set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (s->dma_dac.enabled)
-				start_dac(s);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			if (!schedule_timeout(HZ)) {
-				printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				       s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count, 
-				       s->dma_dac.hwptr, s->dma_dac.swptr);
-				stop_dac(s);
-				spin_lock_irqsave(&s->lock, flags);
-				set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
-				/* program enhanced mode registers */
-				wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
-				wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1);
-				s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
-				spin_unlock_irqrestore(&s->lock, flags);
-			}
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		swptr = (swptr + cnt) % s->dma_dac.dmasize;
-		spin_lock_irqsave(&s->lock, flags);
-		s->dma_dac.swptr = swptr;
-		s->dma_dac.count += cnt;
-		s->dma_dac.endcleared = 0;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		if (s->dma_dac.enabled)
-			start_dac(s);
-	}
-        remove_wait_queue(&s->dma_dac.wait, &wait);
-	set_current_state(TASK_RUNNING);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE) {
-		if (!s->dma_dac.ready && prog_dmabuf(s, 1))
-			return 0;
-		poll_wait(file, &s->dma_dac.wait, wait);
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!s->dma_adc.ready && prog_dmabuf(s, 0))
-			return 0;
-		poll_wait(file, &s->dma_adc.wait, wait);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	sv_update_ptr(s);
-	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->dma_dac.mapped) {
-			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int sv_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	struct dmabuf *db;
-	int ret = -EINVAL;
-	unsigned long size;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf(s, 1)) != 0)
-			goto out;
-		db = &s->dma_dac;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf(s, 0)) != 0)
-			goto out;
-		db = &s->dma_adc;
-	} else 
-		goto out;
-	ret = -EINVAL;
-	if (vma->vm_pgoff != 0)
-		goto out;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << db->buforder))
-		goto out;
-	ret = -EAGAIN;
-	if (remap_pfn_range(vma, vma->vm_start,
-				virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
-				size, vma->vm_page_prot))
-		goto out;
-	db->mapped = 1;
-	ret = 0;
-out:
-	unlock_kernel();
-	return ret;
-}
-
-static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	unsigned long flags;
-        audio_buf_info abinfo;
-        count_info cinfo;
-	int count;
-	int val, mapped, ret;
-	unsigned char fmtm, fmtd;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	VALIDATE_STATE(s);
-        mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
-		((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-	switch (cmd) {
-	case OSS_GETVERSION:
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_SYNC:
-		if (file->f_mode & FMODE_WRITE)
-			return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
-		return 0;
-		
-	case SNDCTL_DSP_SETDUPLEX:
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-		
-        case SNDCTL_DSP_RESET:
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			synchronize_irq(s->irq);
-			s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
-		}
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			synchronize_irq(s->irq);
-			s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SPEED:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val >= 0) {
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				set_adc_rate(s, val);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				set_dac_rate(s, val);
-			}
-		}
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-		
-        case SNDCTL_DSP_STEREO:
-                if (get_user(val, p))
-			return -EFAULT;
-		fmtd = 0;
-		fmtm = ~0;
-		if (file->f_mode & FMODE_READ) {
-			stop_adc(s);
-			s->dma_adc.ready = 0;
-			if (val)
-				fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
-			else
-				fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			stop_dac(s);
-			s->dma_dac.ready = 0;
-			if (val)
-				fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
-			else
-				fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
-		}
-		set_fmt(s, fmtm, fmtd);
-		return 0;
-
-        case SNDCTL_DSP_CHANNELS:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 0) {
-			fmtd = 0;
-			fmtm = ~0;
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val >= 2)
-					fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
-				else
-					fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val >= 2)
-					fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
-				else
-					fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
-			}
-			set_fmt(s, fmtm, fmtd);
-		}
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) 
-					   : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p);
-		
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask */
-                return put_user(AFMT_S16_LE|AFMT_U8, p);
-		
-	case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
-		if (get_user(val, p))
-			return -EFAULT;
-		if (val != AFMT_QUERY) {
-			fmtd = 0;
-			fmtm = ~0;
-			if (file->f_mode & FMODE_READ) {
-				stop_adc(s);
-				s->dma_adc.ready = 0;
-				if (val == AFMT_S16_LE)
-					fmtd |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
-				else
-					fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_CSHIFT);
-			}
-			if (file->f_mode & FMODE_WRITE) {
-				stop_dac(s);
-				s->dma_dac.ready = 0;
-				if (val == AFMT_S16_LE)
-					fmtd |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
-				else
-					fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_ASHIFT);
-			}
-			set_fmt(s, fmtm, fmtd);
-		}
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) 
-					   : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, p);
-		
-	case SNDCTL_DSP_POST:
-                return 0;
-
-        case SNDCTL_DSP_GETTRIGGER:
-		val = 0;
-		if (file->f_mode & FMODE_READ && s->enable & SV_CENABLE_RE) 
-			val |= PCM_ENABLE_INPUT;
-		if (file->f_mode & FMODE_WRITE && s->enable & SV_CENABLE_PE) 
-			val |= PCM_ENABLE_OUTPUT;
-		return put_user(val, p);
-		
-	case SNDCTL_DSP_SETTRIGGER:
-		if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			if (val & PCM_ENABLE_INPUT) {
-				if (!s->dma_adc.ready && (ret =  prog_dmabuf(s, 1)))
-					return ret;
-				s->dma_adc.enabled = 1;
-				start_adc(s);
-			} else {
-				s->dma_adc.enabled = 0;
-				stop_adc(s);
-			}
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			if (val & PCM_ENABLE_OUTPUT) {
-				if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
-					return ret;
-				s->dma_dac.enabled = 1;
-				start_dac(s);
-			} else {
-				s->dma_dac.enabled = 0;
-				stop_dac(s);
-			}
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		sv_update_ptr(s);
-		abinfo.fragsize = s->dma_dac.fragsize;
-		count = s->dma_dac.count;
-		if (count < 0)
-			count = 0;
-                abinfo.bytes = s->dma_dac.dmasize - count;
-                abinfo.fragstotal = s->dma_dac.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		sv_update_ptr(s);
-		abinfo.fragsize = s->dma_adc.fragsize;
-		count = s->dma_adc.count;
-		if (count < 0)
-			count = 0;
-                abinfo.bytes = count;
-                abinfo.fragstotal = s->dma_adc.numfrag;
-                abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;      
-		spin_unlock_irqrestore(&s->lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-		
-        case SNDCTL_DSP_NONBLOCK:
-                file->f_flags |= O_NONBLOCK;
-                return 0;
-
-        case SNDCTL_DSP_GETODELAY:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		sv_update_ptr(s);
-                count = s->dma_dac.count;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (count < 0)
-			count = 0;
-		return put_user(count, p);
-
-        case SNDCTL_DSP_GETIPTR:
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		sv_update_ptr(s);
-                cinfo.bytes = s->dma_adc.total_bytes;
-		count = s->dma_adc.count;
-		if (count < 0)
-			count = 0;
-                cinfo.blocks = count >> s->dma_adc.fragshift;
-                cinfo.ptr = s->dma_adc.hwptr;
-		if (s->dma_adc.mapped)
-			s->dma_adc.count &= s->dma_adc.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETOPTR:
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
-			return val;
-		spin_lock_irqsave(&s->lock, flags);
-		sv_update_ptr(s);
-                cinfo.bytes = s->dma_dac.total_bytes;
-		count = s->dma_dac.count;
-		if (count < 0)
-			count = 0;
-                cinfo.blocks = count >> s->dma_dac.fragshift;
-                cinfo.ptr = s->dma_dac.hwptr;
-		if (s->dma_dac.mapped)
-			s->dma_dac.count &= s->dma_dac.fragsize-1;
-		spin_unlock_irqrestore(&s->lock, flags);
-                if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
-			return -EFAULT;
-		return 0;
-
-        case SNDCTL_DSP_GETBLKSIZE:
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf(s, 0)))
-				return val;
-			return put_user(s->dma_dac.fragsize, p);
-		}
-		if ((val = prog_dmabuf(s, 1)))
-			return val;
-		return put_user(s->dma_adc.fragsize, p);
-
-        case SNDCTL_DSP_SETFRAGMENT:
-                if (get_user(val, p))
-			return -EFAULT;
-		if (file->f_mode & FMODE_READ) {
-			s->dma_adc.ossfragshift = val & 0xffff;
-			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_adc.ossfragshift < 4)
-				s->dma_adc.ossfragshift = 4;
-			if (s->dma_adc.ossfragshift > 15)
-				s->dma_adc.ossfragshift = 15;
-			if (s->dma_adc.ossmaxfrags < 4)
-				s->dma_adc.ossmaxfrags = 4;
-		}
-		if (file->f_mode & FMODE_WRITE) {
-			s->dma_dac.ossfragshift = val & 0xffff;
-			s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
-			if (s->dma_dac.ossfragshift < 4)
-				s->dma_dac.ossfragshift = 4;
-			if (s->dma_dac.ossfragshift > 15)
-				s->dma_dac.ossfragshift = 15;
-			if (s->dma_dac.ossmaxfrags < 4)
-				s->dma_dac.ossmaxfrags = 4;
-		}
-		return 0;
-
-        case SNDCTL_DSP_SUBDIVIDE:
-		if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
-		    (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
-			return -EINVAL;
-                if (get_user(val, p))
-			return -EFAULT;
-		if (val != 1 && val != 2 && val != 4)
-			return -EINVAL;
-		if (file->f_mode & FMODE_READ)
-			s->dma_adc.subdivision = val;
-		if (file->f_mode & FMODE_WRITE)
-			s->dma_dac.subdivision = val;
-		return 0;
-
-        case SOUND_PCM_READ_RATE:
-		return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
-        case SOUND_PCM_READ_CHANNELS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT) 
-					   : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p);
-
-        case SOUND_PCM_READ_BITS:
-		return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT) 
-					   : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, p);
-
-        case SOUND_PCM_WRITE_FILTER:
-        case SNDCTL_DSP_SETSYNCRO:
-        case SOUND_PCM_READ_FILTER:
-                return -EINVAL;
-		
-	}
-	return mixer_ioctl(s, cmd, arg);
-}
-
-static int sv_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned char fmtm = ~0, fmts = 0;
-	struct list_head *list;
-	struct sv_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct sv_state, devs);
-		if (!((s->dev_audio ^ minor) & ~0xf))
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & file->f_mode) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	if (file->f_mode & FMODE_READ) {
-		fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_CSHIFT);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
-		s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
-		s->dma_adc.enabled = 1;
-		set_adc_rate(s, 8000);
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_ASHIFT);
-		if ((minor & 0xf) == SND_DEV_DSP16)
-			fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
-		s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
-		s->dma_dac.enabled = 1;
-		set_dac_rate(s, 8000);
-	}
-	set_fmt(s, fmtm, fmts);
-	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int sv_release(struct inode *inode, struct file *file)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE)
-		drain_dac(s, file->f_flags & O_NONBLOCK);
-	mutex_lock(&s->open_mutex);
-	if (file->f_mode & FMODE_WRITE) {
-		stop_dac(s);
-		dealloc_dmabuf(s, &s->dma_dac);
-	}
-	if (file->f_mode & FMODE_READ) {
-		stop_adc(s);
-		dealloc_dmabuf(s, &s->dma_adc);
-	}
-	s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations sv_audio_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= sv_read,
-	.write		= sv_write,
-	.poll		= sv_poll,
-	.ioctl		= sv_ioctl,
-	.mmap		= sv_mmap,
-	.open		= sv_open,
-	.release	= sv_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t sv_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_WRITE, buffer, count))
-		return -EFAULT;
-	if (count == 0)
-		return 0;
-	ret = 0;
-	add_wait_queue(&s->midi.iwait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.ird;
-		cnt = MIDIINBUF - ptr;
-		if (s->midi.icnt < cnt)
-			cnt = s->midi.icnt;
-		if (cnt <= 0)
-                      __set_current_state(TASK_INTERRUPTIBLE);
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-                      if (file->f_flags & O_NONBLOCK) {
-                              if (!ret)
-                                      ret = -EAGAIN;
-                              break;
-                      }
-                      schedule();
-                      if (signal_pending(current)) {
-                              if (!ret)
-                                      ret = -ERESTARTSYS;
-                              break;
-                      }
-			continue;
-		}
-		if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		ptr = (ptr + cnt) % MIDIINBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.ird = ptr;
-		s->midi.icnt -= cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		break;
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&s->midi.iwait, &wait);
-	return ret;
-}
-
-static ssize_t sv_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned ptr;
-	int cnt;
-
-	VALIDATE_STATE(s);
-	if (!access_ok(VERIFY_READ, buffer, count))
-		return -EFAULT;
-	if (count == 0)
-		return 0;
-	ret = 0;
-        add_wait_queue(&s->midi.owait, &wait);
-	while (count > 0) {
-		spin_lock_irqsave(&s->lock, flags);
-		ptr = s->midi.owr;
-		cnt = MIDIOUTBUF - ptr;
-		if (s->midi.ocnt + cnt > MIDIOUTBUF)
-			cnt = MIDIOUTBUF - s->midi.ocnt;
-		if (cnt <= 0) {
-			__set_current_state(TASK_INTERRUPTIBLE);
-			sv_handle_midi(s);
-		}
-		spin_unlock_irqrestore(&s->lock, flags);
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret)
-					ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			if (signal_pending(current)) {
-				if (!ret)
-					ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
-			if (!ret)
-				ret = -EFAULT;
-			break;
-		}
-		ptr = (ptr + cnt) % MIDIOUTBUF;
-		spin_lock_irqsave(&s->lock, flags);
-		s->midi.owr = ptr;
-		s->midi.ocnt += cnt;
-		spin_unlock_irqrestore(&s->lock, flags);
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		spin_lock_irqsave(&s->lock, flags);
-		sv_handle_midi(s);
-		spin_unlock_irqrestore(&s->lock, flags);
-	}
-	__set_current_state(TASK_RUNNING);
-	remove_wait_queue(&s->midi.owait, &wait);
-	return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int sv_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	VALIDATE_STATE(s);
-	if (file->f_mode & FMODE_WRITE)
-		poll_wait(file, &s->midi.owait, wait);
-	if (file->f_mode & FMODE_READ)
-		poll_wait(file, &s->midi.iwait, wait);
-	spin_lock_irqsave(&s->lock, flags);
-	if (file->f_mode & FMODE_READ) {
-		if (s->midi.icnt > 0)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		if (s->midi.ocnt < MIDIOUTBUF)
-			mask |= POLLOUT | POLLWRNORM;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	return mask;
-}
-
-static int sv_midi_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	struct list_head *list;
-	struct sv_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct sv_state, devs);
-		if (s->dev_midi == minor)
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-		//outb(inb(s->ioenh + SV_CODEC_CONTROL) | SV_CCTRL_WAVETABLE, s->ioenh + SV_CODEC_CONTROL);
-		outb(inb(s->ioenh + SV_CODEC_INTMASK) | SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
-		wrindir(s, SV_CIUARTCONTROL, 5); /* output MIDI data to external and internal synth */
-		wrindir(s, SV_CIWAVETABLESRC, 1); /* Wavetable in PC RAM */
-		outb(0xff, s->iomidi+1); /* reset command */
-		outb(0x3f, s->iomidi+1); /* uart command */
-		if (!(inb(s->iomidi+1) & 0x80))
-			inb(s->iomidi);
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-		init_timer(&s->midi.timer);
-		s->midi.timer.expires = jiffies+1;
-		s->midi.timer.data = (unsigned long)s;
-		s->midi.timer.function = sv_midi_timer;
-		add_timer(&s->midi.timer);
-	}
-	if (file->f_mode & FMODE_READ) {
-		s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int sv_midi_release(struct inode *inode, struct file *file)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	DECLARE_WAITQUEUE(wait, current);
-	unsigned long flags;
-	unsigned count, tmo;
-
-	VALIDATE_STATE(s);
-
-	lock_kernel();
-	if (file->f_mode & FMODE_WRITE) {
-		add_wait_queue(&s->midi.owait, &wait);
-		for (;;) {
-			__set_current_state(TASK_INTERRUPTIBLE);
-			spin_lock_irqsave(&s->lock, flags);
-			count = s->midi.ocnt;
-			spin_unlock_irqrestore(&s->lock, flags);
-			if (count <= 0)
-				break;
-			if (signal_pending(current))
-				break;
-			if (file->f_flags & O_NONBLOCK) {
-				remove_wait_queue(&s->midi.owait, &wait);
-				set_current_state(TASK_RUNNING);
-				unlock_kernel();
-				return -EBUSY;
-			}
-			tmo = (count * HZ) / 3100;
-			if (!schedule_timeout(tmo ? : 1) && tmo)
-				printk(KERN_DEBUG "sv: midi timed out??\n");
-		}
-		remove_wait_queue(&s->midi.owait, &wait);
-		set_current_state(TASK_RUNNING);
-	}
-	mutex_lock(&s->open_mutex);
-	s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
-	spin_lock_irqsave(&s->lock, flags);
-	if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
-		outb(inb(s->ioenh + SV_CODEC_INTMASK) & ~SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
-		del_timer(&s->midi.timer);		
-	}
-	spin_unlock_irqrestore(&s->lock, flags);
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations sv_midi_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= sv_midi_read,
-	.write		= sv_midi_write,
-	.poll		= sv_midi_poll,
-	.open		= sv_midi_open,
-	.release	= sv_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int sv_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
-	static const unsigned char op_offset[18] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
-		0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
-		0x10, 0x11, 0x12, 0x13, 0x14, 0x15
-	};
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	struct dm_fm_voice v;
-	struct dm_fm_note n;
-	struct dm_fm_params p;
-	unsigned int io;
-	unsigned int regb;
-
-	switch (cmd) {		
-	case FM_IOCTL_RESET:
-		for (regb = 0xb0; regb < 0xb9; regb++) {
-			outb(regb, s->iosynth);
-			outb(0, s->iosynth+1);
-			outb(regb, s->iosynth+2);
-			outb(0, s->iosynth+3);
-		}
-		return 0;
-
-	case FM_IOCTL_PLAY_NOTE:
-		if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
-			return -EFAULT;
-		if (n.voice >= 18)
-			return -EINVAL;
-		if (n.voice >= 9) {
-			regb = n.voice - 9;
-			io = s->iosynth+2;
-		} else {
-			regb = n.voice;
-			io = s->iosynth;
-		}
-		outb(0xa0 + regb, io);
-		outb(n.fnum & 0xff, io+1);
-		outb(0xb0 + regb, io);
-		outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
-		return 0;
-
-	case FM_IOCTL_SET_VOICE:
-		if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
-			return -EFAULT;
-		if (v.voice >= 18)
-			return -EINVAL;
-		regb = op_offset[v.voice];
-		io = s->iosynth + ((v.op & 1) << 1);
-		outb(0x20 + regb, io);
-		outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) | 
-		     ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
-		outb(0x40 + regb, io);
-		outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
-		outb(0x60 + regb, io);
-		outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
-		outb(0x80 + regb, io);
-		outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
-		outb(0xe0 + regb, io);
-		outb(v.waveform & 0x7, io+1);
-		if (n.voice >= 9) {
-			regb = n.voice - 9;
-			io = s->iosynth+2;
-		} else {
-			regb = n.voice;
-			io = s->iosynth;
-		}
-		outb(0xc0 + regb, io);
-		outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
-		     (v.connection & 1), io+1);
-		return 0;
-		
-	case FM_IOCTL_SET_PARAMS:
-		if (copy_from_user(&p, (void *__user )arg, sizeof(p)))
-			return -EFAULT;
-		outb(0x08, s->iosynth);
-		outb((p.kbd_split & 1) << 6, s->iosynth+1);
-		outb(0xbd, s->iosynth);
-		outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
-		     ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->iosynth+1);
-		return 0;
-
-	case FM_IOCTL_SET_OPL:
-		outb(4, s->iosynth+2);
-		outb(arg, s->iosynth+3);
-		return 0;
-
-	case FM_IOCTL_SET_MODE:
-		outb(5, s->iosynth+2);
-		outb(arg & 1, s->iosynth+3);
-		return 0;
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int sv_dmfm_open(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	DECLARE_WAITQUEUE(wait, current);
-	struct list_head *list;
-	struct sv_state *s;
-
-	for (list = devs.next; ; list = list->next) {
-		if (list == &devs)
-			return -ENODEV;
-		s = list_entry(list, struct sv_state, devs);
-		if (s->dev_dmfm == minor)
-			break;
-	}
-       	VALIDATE_STATE(s);
-	file->private_data = s;
-	/* wait for device to become free */
-	mutex_lock(&s->open_mutex);
-	while (s->open_mode & FMODE_DMFM) {
-		if (file->f_flags & O_NONBLOCK) {
-			mutex_unlock(&s->open_mutex);
-			return -EBUSY;
-		}
-		add_wait_queue(&s->open_wait, &wait);
-		__set_current_state(TASK_INTERRUPTIBLE);
-		mutex_unlock(&s->open_mutex);
-		schedule();
-		remove_wait_queue(&s->open_wait, &wait);
-		set_current_state(TASK_RUNNING);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		mutex_lock(&s->open_mutex);
-	}
-	/* init the stuff */
-	outb(1, s->iosynth);
-	outb(0x20, s->iosynth+1); /* enable waveforms */
-	outb(4, s->iosynth+2);
-	outb(0, s->iosynth+3);  /* no 4op enabled */
-	outb(5, s->iosynth+2);
-	outb(1, s->iosynth+3);  /* enable OPL3 */
-	s->open_mode |= FMODE_DMFM;
-	mutex_unlock(&s->open_mutex);
-	return nonseekable_open(inode, file);
-}
-
-static int sv_dmfm_release(struct inode *inode, struct file *file)
-{
-	struct sv_state *s = (struct sv_state *)file->private_data;
-	unsigned int regb;
-
-	VALIDATE_STATE(s);
-	lock_kernel();
-	mutex_lock(&s->open_mutex);
-	s->open_mode &= ~FMODE_DMFM;
-	for (regb = 0xb0; regb < 0xb9; regb++) {
-		outb(regb, s->iosynth);
-		outb(0, s->iosynth+1);
-		outb(regb, s->iosynth+2);
-		outb(0, s->iosynth+3);
-	}
-	wake_up(&s->open_wait);
-	mutex_unlock(&s->open_mutex);
-	unlock_kernel();
-	return 0;
-}
-
-static /*const*/ struct file_operations sv_dmfm_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= sv_dmfm_ioctl,
-	.open		= sv_dmfm_open,
-	.release	= sv_dmfm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int reverb[NR_DEVICE];
-
-#if 0
-static int wavetable[NR_DEVICE];
-#endif
-
-static unsigned int devindex;
-
-module_param_array(reverb, bool, NULL, 0);
-MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
-#if 0
-MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i");
-MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled");
-#endif
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("S3 SonicVibes Driver");
-MODULE_LICENSE("GPL");
-
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
-	int mixch;
-	int vol;
-} initvol[] __devinitdata = {
-	{ SOUND_MIXER_WRITE_RECLEV, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE1, 0x4040 },
-	{ SOUND_MIXER_WRITE_CD, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE, 0x4040 },
-	{ SOUND_MIXER_WRITE_MIC, 0x4040 },
-	{ SOUND_MIXER_WRITE_SYNTH, 0x4040 },
-	{ SOUND_MIXER_WRITE_LINE2, 0x4040 },
-	{ SOUND_MIXER_WRITE_VOLUME, 0x4040 },
-	{ SOUND_MIXER_WRITE_PCM, 0x4040 }
-};
-
-#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
-				 (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
-
-#ifdef SUPPORT_JOYSTICK
-static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
-{
-	struct gameport *gp;
-
-	if (!request_region(io_port, SV_EXTENT_GAME, "S3 SonicVibes Gameport")) {
-		printk(KERN_ERR "sv: gameport io ports are in use\n");
-		return -EBUSY;
-	}
-
-	s->gameport = gp = gameport_allocate_port();
-	if (!gp) {
-		printk(KERN_ERR "sv: can not allocate memory for gameport\n");
-		release_region(io_port, SV_EXTENT_GAME);
-		return -ENOMEM;
-	}
-
-	gameport_set_name(gp, "S3 SonicVibes Gameport");
-	gameport_set_phys(gp, "isa%04x/gameport0", io_port);
-	gp->dev.parent = &s->dev->dev;
-	gp->io = io_port;
-
-	gameport_register_port(gp);
-
-	return 0;
-}
-
-static inline void sv_unregister_gameport(struct sv_state *s)
-{
-	if (s->gameport) {
-		int gpio = s->gameport->io;
-		gameport_unregister_port(s->gameport);
-		release_region(gpio, SV_EXTENT_GAME);
-	}
-}
-#else
-static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; }
-static inline void sv_unregister_gameport(struct sv_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
-	static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
-       	struct sv_state *s;
-	mm_segment_t fs;
-	int i, val, ret;
-	int gpio;
-	char *ddmaname;
-	unsigned ddmanamelen;
-
-	if ((ret=pci_enable_device(pcidev)))
-		return ret;
-
-	if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
-	    !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
-	    !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
-	    !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
-	    !RSRCISIOREGION(pcidev, RESOURCE_GAME))
-		return -ENODEV;
-	if (pcidev->irq == 0)
-		return -ENODEV;
-	if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK)) {
-		printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
-		return -ENODEV;
-	}
-	/* try to allocate a DDMA resource if not already available */
-	if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
-		pcidev->resource[RESOURCE_DDMA].start = 0;
-		pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1;
-		pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
-		ddmanamelen = strlen(sv_ddma_name)+1;
-		if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
-			return -1;
-		memcpy(ddmaname, sv_ddma_name, ddmanamelen);
-		pcidev->resource[RESOURCE_DDMA].name = ddmaname;
-		if (pci_assign_resource(pcidev, RESOURCE_DDMA)) {
-			pcidev->resource[RESOURCE_DDMA].name = NULL;
-			kfree(ddmaname);
-			printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
-			return -EBUSY;
-		}
-	}
-	if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
-		printk(KERN_WARNING "sv: out of memory\n");
-		return -ENOMEM;
-	}
-	memset(s, 0, sizeof(struct sv_state));
-	init_waitqueue_head(&s->dma_adc.wait);
-	init_waitqueue_head(&s->dma_dac.wait);
-	init_waitqueue_head(&s->open_wait);
-	init_waitqueue_head(&s->midi.iwait);
-	init_waitqueue_head(&s->midi.owait);
-	mutex_init(&s->open_mutex);
-	spin_lock_init(&s->lock);
-	s->magic = SV_MAGIC;
-	s->dev = pcidev;
-	s->iosb = pci_resource_start(pcidev, RESOURCE_SB);
-	s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH);
-	s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH);
-	s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI);
-	s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA);
-	s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
-	gpio = pci_resource_start(pcidev, RESOURCE_GAME);
-	pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9);  /* enable and use extended mode */
-	pci_write_config_dword(pcidev, 0x48, s->iodmac | 9);  /* enable */
-	printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n",
-	       s->iosb, s->ioenh, s->iosynth, s->iomidi, gpio, s->iodmaa, s->iodmac);
-	s->irq = pcidev->irq;
-	
-	/* hack */
-	pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12);  /* wavetable base address */
-
-	ret = -EBUSY;
-	if (!request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM")) {
-		printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1);
-		goto err_region5;
-	}
-	if (!request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA")) {
-		printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1);
-		goto err_region4;
-	}
-	if (!request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC")) {
-		printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1);
-		goto err_region3;
-	}
-	if (!request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi")) {
-		printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1);
-		goto err_region2;
-	}
-	if (!request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth")) {
-		printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
-		goto err_region1;
-	}
-
-	/* initialize codec registers */
-	outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
-	udelay(50);
-	outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */
-	udelay(50);
-	outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */
-	     | (reverb[devindex] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL);
-	inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */
-	wrindir(s, SV_CIDRIVECONTROL, 0);  /* drive current 16mA */
-	wrindir(s, SV_CIENABLE, s->enable = 0);  /* disable DMAA and DMAC */
-	outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
-	/* outb(0xff, s->iodmaa + SV_DMA_RESET); */
-	/* outb(0xff, s->iodmac + SV_DMA_RESET); */
-	inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
-	wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
-	wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
-	wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */
-	setpll(s, SV_CIADCPLLM, 8000);
-	wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */
-	wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff);
-	wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff);
-	wrindir(s, SV_CIADCOUTPUT, 0);
-	/* request irq */
-	if ((ret=request_irq(s->irq,sv_interrupt,IRQF_SHARED,"S3 SonicVibes",s))) {
-		printk(KERN_ERR "sv: irq %u in use\n", s->irq);
-		goto err_irq;
-	}
-	printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n",
-	       s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION));
-	/* register devices */
-	if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) {
-		ret = s->dev_audio;
-		goto err_dev1;
-	}
-	if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0) {
-		ret = s->dev_mixer;
-		goto err_dev2;
-	}
-	if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0) {
-		ret = s->dev_midi;
-		goto err_dev3;
-	}
-	if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) {
-		ret = s->dev_dmfm;
-		goto err_dev4;
-	}
-	pci_set_master(pcidev);  /* enable bus mastering */
-	/* initialize the chips */
-	fs = get_fs();
-	set_fs(KERNEL_DS);
-	val = SOUND_MASK_LINE|SOUND_MASK_SYNTH;
-	mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
-	for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
-		val = initvol[i].vol;
-		mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
-	}
-	set_fs(fs);
-	/* register gameport */
-	sv_register_gameport(s, gpio);
-	/* store it in the driver field */
-	pci_set_drvdata(pcidev, s);
-	/* put it into driver list */
-	list_add_tail(&s->devs, &devs);
-	/* increment devindex */
-	if (devindex < NR_DEVICE-1)
-		devindex++;
-	return 0;
-
- err_dev4:
-	unregister_sound_midi(s->dev_midi);
- err_dev3:
-	unregister_sound_mixer(s->dev_mixer);
- err_dev2:
-	unregister_sound_dsp(s->dev_audio);
- err_dev1:
-	printk(KERN_ERR "sv: cannot register misc device\n");
-	free_irq(s->irq, s);
- err_irq:
-	release_region(s->iosynth, SV_EXTENT_SYNTH);
- err_region1:
-	release_region(s->iomidi, SV_EXTENT_MIDI);
- err_region2:
-	release_region(s->iodmac, SV_EXTENT_DMA);
- err_region3:
-	release_region(s->iodmaa, SV_EXTENT_DMA);
- err_region4:
-	release_region(s->ioenh, SV_EXTENT_ENH);
- err_region5:
-	kfree(s);
-	return ret;
-}
-
-static void __devexit sv_remove(struct pci_dev *dev)
-{
-	struct sv_state *s = pci_get_drvdata(dev);
-
-	if (!s)
-		return;
-	list_del(&s->devs);
-	outb(~0, s->ioenh + SV_CODEC_INTMASK);  /* disable ints */
-	synchronize_irq(s->irq);
-	inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
-	wrindir(s, SV_CIENABLE, 0);     /* disable DMAA and DMAC */
-	/*outb(0, s->iodmaa + SV_DMA_RESET);*/
-	/*outb(0, s->iodmac + SV_DMA_RESET);*/
-	free_irq(s->irq, s);
-	sv_unregister_gameport(s);
-	release_region(s->iodmac, SV_EXTENT_DMA);
-	release_region(s->iodmaa, SV_EXTENT_DMA);
-	release_region(s->ioenh, SV_EXTENT_ENH);
-	release_region(s->iomidi, SV_EXTENT_MIDI);
-	release_region(s->iosynth, SV_EXTENT_SYNTH);
-	unregister_sound_dsp(s->dev_audio);
-	unregister_sound_mixer(s->dev_mixer);
-	unregister_sound_midi(s->dev_midi);
-	unregister_sound_special(s->dev_dmfm);
-	kfree(s);
-	pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
-       { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
-       { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver sv_driver = {
-       .name		= "sonicvibes",
-       .id_table	= id_table,
-       .probe		= sv_probe,
-       .remove		= __devexit_p(sv_remove),
-};
- 
-static int __init init_sonicvibes(void)
-{
-	printk(KERN_INFO "sv: version v0.31 time " __TIME__ " " __DATE__ "\n");
-#if 0
-	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
-		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
-#endif
-	return pci_register_driver(&sv_driver);
-}
-
-static void __exit cleanup_sonicvibes(void)
-{
-	printk(KERN_INFO "sv: unloading\n");
-	pci_unregister_driver(&sv_driver);
- 	if (wavetable_mem)
-		free_pages(wavetable_mem, 20-PAGE_SHIFT);
-}
-
-module_init(init_sonicvibes);
-module_exit(cleanup_sonicvibes);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: sonicvibes=[reverb] sonicvibesdmaio=dmaioaddr */
-
-static int __init sonicvibes_setup(char *str)
-{
-	static unsigned __initdata nr_dev = 0;
-
-	if (nr_dev >= NR_DEVICE)
-		return 0;
-#if 0
-	if (get_option(&str, &reverb[nr_dev]) == 2)
-		(void)get_option(&str, &wavetable[nr_dev]);
-#else
-	(void)get_option(&str, &reverb[nr_dev]);
-#endif
-
-	nr_dev++;
-	return 1;
-}
-
-__setup("sonicvibes=", sonicvibes_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h
index 1ae0750..87d8ad4 100644
--- a/sound/oss/sound_calls.h
+++ b/sound/oss/sound_calls.h
@@ -13,8 +13,6 @@
 void DMAbuf_init(int dev, int dma1, int dma2);
 void DMAbuf_deinit(int dev);
 int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
-int DMAbuf_open_dma (int dev);
-void DMAbuf_close_dma (int dev);
 void DMAbuf_inputintr(int dev);
 void DMAbuf_outputintr(int dev, int underflow_flag);
 struct dma_buffparms;
@@ -73,7 +71,6 @@
 int MIDIbuf_avail(int dev);
 
 void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
-void MIDIbuf_init(void);
 
 
 /*	From soundcard.c	*/
diff --git a/sound/oss/sound_syms.c b/sound/oss/sound_syms.c
deleted file mode 100644
index cb7c33f..0000000
--- a/sound/oss/sound_syms.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *	The sound core exports the following symbols to the rest of
- *	modulespace.
- *
- *      (C) Copyright 1997      Alan Cox, Licensed under the GNU GPL
- *
- *	Thu May 27 1999 Andrew J. Kroll <ag784@freenet..buffalo..edu>
- *	left out exported symbol... fixed
- */
-
-#include <linux/module.h>
-#include "sound_config.h"
-#include "sound_calls.h"
-
-char sound_syms_symbol;
-
-EXPORT_SYMBOL(mixer_devs);
-EXPORT_SYMBOL(audio_devs);
-EXPORT_SYMBOL(num_mixers);
-EXPORT_SYMBOL(num_audiodevs);
-
-EXPORT_SYMBOL(midi_devs);
-EXPORT_SYMBOL(num_midis);
-EXPORT_SYMBOL(synth_devs);
-
-EXPORT_SYMBOL(sound_timer_devs);
-
-EXPORT_SYMBOL(sound_install_audiodrv);
-EXPORT_SYMBOL(sound_install_mixer);
-EXPORT_SYMBOL(sound_alloc_dma);
-EXPORT_SYMBOL(sound_free_dma);
-EXPORT_SYMBOL(sound_open_dma);
-EXPORT_SYMBOL(sound_close_dma);
-EXPORT_SYMBOL(sound_alloc_mididev);
-EXPORT_SYMBOL(sound_alloc_mixerdev);
-EXPORT_SYMBOL(sound_alloc_timerdev);
-EXPORT_SYMBOL(sound_alloc_synthdev);
-EXPORT_SYMBOL(sound_unload_audiodev);
-EXPORT_SYMBOL(sound_unload_mididev);
-EXPORT_SYMBOL(sound_unload_mixerdev);
-EXPORT_SYMBOL(sound_unload_timerdev);
-EXPORT_SYMBOL(sound_unload_synthdev);
-
-EXPORT_SYMBOL(load_mixer_volumes);
-
-EXPORT_SYMBOL(conf_printf);
-EXPORT_SYMBOL(conf_printf2);
-
-MODULE_DESCRIPTION("OSS Sound subsystem");
-MODULE_AUTHOR("Hannu Savolainen, et al.");
diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c
index 146bf85..f0f0c19 100644
--- a/sound/oss/sound_timer.c
+++ b/sound/oss/sound_timer.c
@@ -76,6 +76,7 @@
 	tmr_ctr = 0;
 	usecs_per_tmr = new_usecs;
 }
+EXPORT_SYMBOL(sound_timer_syncinterval);
 
 static void tmr_reset(void)
 {
@@ -300,6 +301,7 @@
 	}
 	spin_unlock_irqrestore(&lock,flags);
 }
+EXPORT_SYMBOL(sound_timer_interrupt);
 
 void  sound_timer_init(struct sound_lowlev_timer *t, char *name)
 {
@@ -321,3 +323,5 @@
 	strcpy(sound_timer.info.name, name);
 	sound_timer_devs[n] = &sound_timer;
 }
+EXPORT_SYMBOL(sound_timer_init);
+
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 683dc00..2344d09 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -107,6 +107,7 @@
 		mixer_vols[n].levels[i] = levels[i];
 	return mixer_vols[n].levels;
 }
+EXPORT_SYMBOL(load_mixer_volumes);
 
 static int set_mixer_levels(void __user * arg)
 {
@@ -541,12 +542,6 @@
 	int             err;
 	int i, j;
 	
-	/* drag in sound_syms.o */
-	{
-		extern char sound_syms_symbol;
-		sound_syms_symbol = 0;
-	}
-
 #ifdef CONFIG_PCI
 	if(dmabug)
 		isa_dma_bridge_buggy = dmabug;
@@ -614,6 +609,8 @@
 module_init(oss_init);
 module_exit(oss_cleanup);
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OSS Sound subsystem");
+MODULE_AUTHOR("Hannu Savolainen, et al.");
 
 
 int sound_alloc_dma(int chn, char *deviceID)
@@ -627,6 +624,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL(sound_alloc_dma);
 
 int sound_open_dma(int chn, char *deviceID)
 {
@@ -642,6 +640,7 @@
 	dma_alloc_map[chn] = DMA_MAP_BUSY;
 	return 0;
 }
+EXPORT_SYMBOL(sound_open_dma);
 
 void sound_free_dma(int chn)
 {
@@ -652,6 +651,7 @@
 	free_dma(chn);
 	dma_alloc_map[chn] = DMA_MAP_UNAVAIL;
 }
+EXPORT_SYMBOL(sound_free_dma);
 
 void sound_close_dma(int chn)
 {
@@ -661,6 +661,7 @@
 	}
 	dma_alloc_map[chn] = DMA_MAP_FREE;
 }
+EXPORT_SYMBOL(sound_close_dma);
 
 static void do_sequencer_timer(unsigned long dummy)
 {
@@ -714,6 +715,7 @@
 	printk("\n");
 #endif
 }
+EXPORT_SYMBOL(conf_printf);
 
 void conf_printf2(char *name, int base, int irq, int dma, int dma2)
 {
@@ -734,3 +736,5 @@
 	printk("\n");
 #endif
 }
+EXPORT_SYMBOL(conf_printf2);
+
diff --git a/sound/oss/tuning.h b/sound/oss/tuning.h
index 858e1fe6..a73e3dd 100644
--- a/sound/oss/tuning.h
+++ b/sound/oss/tuning.h
@@ -1,13 +1,11 @@
-#ifdef SEQUENCER_C
-
-unsigned short semitone_tuning[24] = 
+static unsigned short semitone_tuning[24] =
 {
 /*   0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, 
 /*   8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, 
 /*  16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
 };
 
-unsigned short cent_tuning[100] =
+static unsigned short cent_tuning[100] =
 {
 /*   0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, 
 /*   8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, 
@@ -23,7 +21,3 @@
 /*  88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, 
 /*  96 */ 10570, 10576, 10582, 10589
 };
-#else
-extern unsigned short semitone_tuning[24];
-extern unsigned short cent_tuning[100];
-#endif
diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c
deleted file mode 100644
index 1dec395..0000000
--- a/sound/oss/wavfront.c
+++ /dev/null
@@ -1,3554 +0,0 @@
-/*  -*- linux-c -*-
- *
- * sound/wavfront.c
- *
- * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus)
- *
- * This driver supports the onboard wavetable synthesizer (an ICS2115),
- * including patch, sample and program loading and unloading, conversion
- * of GUS patches during loading, and full user-level access to all
- * WaveFront commands. It tries to provide semi-intelligent patch and
- * sample management as well.
- *
- * It also provides support for the ICS emulation of an MPU-401.  Full
- * support for the ICS emulation's "virtual MIDI mode" is provided in
- * wf_midi.c.
- *
- * Support is also provided for the Tropez Plus' onboard FX processor,
- * a Yamaha YSS225. Currently, code exists to configure the YSS225,
- * and there is an interface allowing tweaking of any of its memory
- * addresses. However, I have been unable to decipher the logical
- * positioning of the configuration info for various effects, so for
- * now, you just get the YSS225 in the same state as Turtle Beach's
- * "SETUPSND.EXE" utility leaves it.
- *
- * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co],
- * This chip also controls the configuration of the card: the wavefront
- * synth is logical unit 4.
- *
- *
- * Supported devices:
- *
- *   /dev/dsp                      - using cs4232+ad1848 modules, OSS compatible
- *   /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible
- *   /dev/synth00                  - raw synth interface
- * 
- **********************************************************************
- *
- * Copyright (C) by Paul Barton-Davis 1998
- *
- * Some portions of this file are taken from work that is
- * copyright (C) by Hannu Savolainen 1993-1996
- *
- * Although the relevant code here is all new, the handling of
- * sample/alias/multi- samples is entirely based on a driver by Matt
- * Martin and Rutger Nijlunsing which demonstrated how to get things
- * to work correctly. The GUS patch loading code has been almost
- * unaltered by me, except to fit formatting and function names in the
- * rest of the file. Many thanks to them.
- *
- * Appreciation and thanks to Hannu Savolainen for his early work on the Maui
- * driver, and answering a few questions while this one was developed.
- *
- * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their
- * complete lack of help in developing this driver, and in particular
- * for their utter silence in response to questions about undocumented
- * aspects of configuring a WaveFront soundcard, particularly the
- * effects processor.
- *
- * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $
- *
- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * 11-10-2000	Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- *		Added some __init and __initdata to entries in yss225.c
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#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>
-#include <linux/config.h>
-
-#include <linux/delay.h>
-
-#include "sound_config.h"
-
-#include <linux/wavefront.h>
-
-#define _MIDI_SYNTH_C_
-#define MIDI_SYNTH_NAME	"WaveFront MIDI"
-#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-/* Compile-time control of the extent to which OSS is supported.
-
-   I consider /dev/sequencer to be an anachronism, but given its
-   widespread usage by various Linux MIDI software, it seems worth
-   offering support to it if it's not too painful. Instead of using
-   /dev/sequencer, I recommend:
-
-     for synth programming and patch loading: /dev/synthNN
-     for kernel-synchronized MIDI sequencing: the ALSA sequencer
-     for direct MIDI control: /dev/midiNN
-
-   I have never tried static compilation into the kernel. The #if's
-   for this are really just notes to myself about what the code is
-   for.
-*/
-
-#define OSS_SUPPORT_SEQ            0x1  /* use of /dev/sequencer */
-#define OSS_SUPPORT_STATIC_INSTALL 0x2  /* static compilation into kernel */
-
-#define OSS_SUPPORT_LEVEL          0x1  /* just /dev/sequencer for now */
-
-#if    OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-static int (*midi_load_patch) (int devno, int format, const char __user *addr,
-			       int offs, int count, int pmgr_flag) = NULL;
-#endif /* OSS_SUPPORT_SEQ */
-
-/* if WF_DEBUG not defined, no run-time debugging messages will
-   be available via the debug flag setting. Given the current
-   beta state of the driver, this will remain set until a future 
-   version.
-*/
-
-#define WF_DEBUG 1
-
-#ifdef WF_DEBUG
-
-/* Thank goodness for gcc's preprocessor ... */
-
-#define DPRINT(cond, format, args...) \
-       if ((dev.debug & (cond)) == (cond)) { \
-	     printk (KERN_DEBUG LOGNAME format, ## args); \
-       }
-#else
-#define DPRINT(cond, format, args...)
-#endif
-
-#define LOGNAME "WaveFront: "
-
-/* bitmasks for WaveFront status port value */
-
-#define STAT_RINTR_ENABLED	0x01
-#define STAT_CAN_READ		0x02
-#define STAT_INTR_READ		0x04
-#define STAT_WINTR_ENABLED	0x10
-#define STAT_CAN_WRITE		0x20
-#define STAT_INTR_WRITE		0x40
-
-/*** Module-accessible parameters ***************************************/
-
-static int wf_raw;     /* we normally check for "raw state" to firmware
-			   loading. if set, then during driver loading, the
-			   state of the board is ignored, and we reset the
-			   board and load the firmware anyway.
-			*/
-		   
-static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in
-		          whatever state it is when the driver is loaded.
-		          The default is to download the microprogram and
-		          associated coefficients to set it up for "default"
-		          operation, whatever that means.
-		       */
-
-static int debug_default;  /* you can set this to control debugging
-			      during driver loading. it takes any combination
-			      of the WF_DEBUG_* flags defined in
-			      wavefront.h
-			   */
-
-/* XXX this needs to be made firmware and hardware version dependent */
-
-static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed
-					            version of the WaveFront OS
-					          */
-
-static int wait_polls = 2000; /* This is a number of tries we poll the
-				 status register before resorting to sleeping.
-				 WaveFront being an ISA card each poll takes
-				 about 1.2us. So before going to
-			         sleep we wait up to 2.4ms in a loop.
-			     */
-
-static int sleep_length = HZ/100; /* This says how long we're going to
-				     sleep between polls.
-			             10ms sounds reasonable for fast response.
-			          */
-
-static int sleep_tries = 50;       /* Wait for status 0.5 seconds total. */
-
-static int reset_time = 2; /* hundreths of a second we wait after a HW reset for
-			      the expected interrupt.
-			   */
-
-static int ramcheck_time = 20;    /* time in seconds to wait while ROM code
-			             checks on-board RAM.
-			          */
-
-static int osrun_time = 10;  /* time in seconds we wait for the OS to
-			        start running.
-			     */
-
-module_param(wf_raw, int, 0);
-module_param(fx_raw, int, 0);
-module_param(debug_default, int, 0);
-module_param(wait_polls, int, 0);
-module_param(sleep_length, int, 0);
-module_param(sleep_tries, int, 0);
-module_param(ospath, charp, 0);
-module_param(reset_time, int, 0);
-module_param(ramcheck_time, int, 0);
-module_param(osrun_time, int, 0);
-
-/***************************************************************************/
-
-/* Note: because this module doesn't export any symbols, this really isn't
-   a global variable, even if it looks like one. I was quite confused by
-   this when I started writing this as a (newer) module -- pbd.
-*/
-
-struct wf_config {
-	int devno;            /* device number from kernel */
-	int irq;              /* "you were one, one of the few ..." */
-	int base;             /* low i/o port address */
-
-#define mpu_data_port    base 
-#define mpu_command_port base + 1 /* write semantics */
-#define mpu_status_port  base + 1 /* read semantics */
-#define data_port        base + 2 
-#define status_port      base + 3 /* read semantics */
-#define control_port     base + 3 /* write semantics  */
-#define block_port       base + 4 /* 16 bit, writeonly */
-#define last_block_port  base + 6 /* 16 bit, writeonly */
-
-	/* FX ports. These are mapped through the ICS2115 to the YS225.
-	   The ICS2115 takes care of flipping the relevant pins on the
-	   YS225 so that access to each of these ports does the right
-	   thing. Note: these are NOT documented by Turtle Beach.
-	*/
-
-#define fx_status       base + 8 
-#define fx_op           base + 8 
-#define fx_lcr          base + 9 
-#define fx_dsp_addr     base + 0xa
-#define fx_dsp_page     base + 0xb 
-#define fx_dsp_lsb      base + 0xc 
-#define fx_dsp_msb      base + 0xd 
-#define fx_mod_addr     base + 0xe
-#define fx_mod_data     base + 0xf 
-
-	volatile int irq_ok;               /* set by interrupt handler */
-        volatile int irq_cnt;              /* ditto */
-	int opened;                        /* flag, holds open(2) mode */
-	char debug;                        /* debugging flags */
-	int freemem;                       /* installed RAM, in bytes */ 
-
-	int synth_dev;                     /* devno for "raw" synth */
-	int mididev;                       /* devno for internal MIDI */
-	int ext_mididev;                   /* devno for external MIDI */ 
-        int fx_mididev;                    /* devno for FX MIDI interface */
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-	int oss_dev;                      /* devno for OSS sequencer synth */
-#endif /* OSS_SUPPORT_SEQ */
-
-	char fw_version[2];                /* major = [0], minor = [1] */
-	char hw_version[2];                /* major = [0], minor = [1] */
-	char israw;                        /* needs Motorola microcode */
-	char has_fx;                       /* has FX processor (Tropez+) */
-	char prog_status[WF_MAX_PROGRAM];  /* WF_SLOT_* */
-	char patch_status[WF_MAX_PATCH];   /* WF_SLOT_* */
-	char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
-	int samples_used;                  /* how many */
-	char interrupts_on;                /* h/w MPU interrupts enabled ? */
-	char rom_samples_rdonly;           /* can we write on ROM samples */
-	wait_queue_head_t interrupt_sleeper; 
-} dev;
-
-static DEFINE_SPINLOCK(lock);
-static int  detect_wffx(void);
-static int  wffx_ioctl (wavefront_fx_info *);
-static int  wffx_init (void);
-
-static int wavefront_delete_sample (int sampnum);
-static int wavefront_find_free_sample (void);
-
-/* From wf_midi.c */
-
-extern int  virtual_midi_enable  (void);
-extern int  virtual_midi_disable (void);
-extern int  detect_wf_mpu (int, int);
-extern int  install_wf_mpu (void);
-extern int  uninstall_wf_mpu (void);
-
-typedef struct {
-	int cmd;
-	char *action;
-	unsigned int read_cnt;
-	unsigned int write_cnt;
-	int need_ack;
-} wavefront_command;
-
-static struct {
-	int errno;
-	const char *errstr;
-} wavefront_errors[] = {
-	{ 0x01, "Bad sample number" },
-	{ 0x02, "Out of sample memory" },
-	{ 0x03, "Bad patch number" },
-	{ 0x04, "Error in number of voices" },
-	{ 0x06, "Sample load already in progress" },
-	{ 0x0B, "No sample load request pending" },
-	{ 0x0E, "Bad MIDI channel number" },
-	{ 0x10, "Download Record Error" },
-	{ 0x80, "Success" },
-	{ 0 }
-};
-
-#define NEEDS_ACK 1
-
-static wavefront_command wavefront_commands[] = {
-	{ WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK },
-	{ WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0},
-	{ WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK },
-	{ WFC_GET_NVOICES, "get number of voices", 1, 0, 0 },
-	{ WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK },
-	{ WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 },
-	{ WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK },
-	{ WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK },
-	{ WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 },
-	{ WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK },
-	{ WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK },
-	{ WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK },
-	{ WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK },
-	{ WFC_MIDI_STATUS, "report midi status", 1, 0, 0 },
-	{ WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 },
-	{ WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 },
-	{ WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 },
-	{ WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 },
-	{ WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 },
-	{ WFC_DOWNLOAD_SAMPLE, "download sample",
-	  0, WF_SAMPLE_BYTES, NEEDS_ACK },
-	{ WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK},
-	{ WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header",
-	  0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK },
-	{ WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 },
-
-	/* This command requires a variable number of bytes to be written.
-	   There is a hack in wavefront_cmd() to support this. The actual
-	   count is passed in as the read buffer ptr, cast appropriately.
-	   Ugh.
-	*/
-
-	{ WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK },
-
-	/* This one is a hack as well. We just read the first byte of the
-	   response, don't fetch an ACK, and leave the rest to the 
-	   calling function. Ugly, ugly, ugly.
-	*/
-
-	{ WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 },
-	{ WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias",
-	  0, WF_ALIAS_BYTES, NEEDS_ACK },
-	{ WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0},
-	{ WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK },
-	{ WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 },
-	{ WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" },
-	{ WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 },
-	{ WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK },
-	{ WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 },
-	{ WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK },
-	{ WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 },
-	{ WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9,
-	  NEEDS_ACK},
-	{ WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0},
-	{ WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel",
-	  0, 1, NEEDS_ACK },
-	{ WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK },
-	{ WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers",
-	  32, 0, 0 },
-	{ WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK },
-	{ 0x00 }
-};
-
-static const char *
-wavefront_errorstr (int errnum)
-
-{
-	int i;
-
-	for (i = 0; wavefront_errors[i].errstr; i++) {
-		if (wavefront_errors[i].errno == errnum) {
-			return wavefront_errors[i].errstr;
-		}
-	}
-
-	return "Unknown WaveFront error";
-}
-
-static wavefront_command *
-wavefront_get_command (int cmd) 
-
-{
-	int i;
-
-	for (i = 0; wavefront_commands[i].cmd != 0; i++) {
-		if (cmd == wavefront_commands[i].cmd) {
-			return &wavefront_commands[i];
-		}
-	}
-
-	return (wavefront_command *) 0;
-}
-
-static inline int
-wavefront_status (void) 
-
-{
-	return inb (dev.status_port);
-}
-
-static int
-wavefront_wait (int mask)
-
-{
-	int i;
-
-	for (i = 0; i < wait_polls; i++)
-		if (wavefront_status() & mask)
-			return 1;
-
-	for (i = 0; i < sleep_tries; i++) {
-
-		if (wavefront_status() & mask) {
-			set_current_state(TASK_RUNNING);
-			return 1;
-		}
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(sleep_length);
-		if (signal_pending(current))
-			break;
-	}
-
-	set_current_state(TASK_RUNNING);
-	return 0;
-}
-
-static int
-wavefront_read (void)
-
-{
-	if (wavefront_wait (STAT_CAN_READ))
-		return inb (dev.data_port);
-
-	DPRINT (WF_DEBUG_DATA, "read timeout.\n");
-
-	return -1;
-}
-
-static int
-wavefront_write (unsigned char data)
-
-{
-	if (wavefront_wait (STAT_CAN_WRITE)) {
-		outb (data, dev.data_port);
-		return 0;
-	}
-
-	DPRINT (WF_DEBUG_DATA, "write timeout.\n");
-
-	return -1;
-}
-
-static int
-wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf)
-
-{
-	int ack;
-	int i;
-	int c;
-	wavefront_command *wfcmd;
-
-	if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) {
-		printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n",
-			cmd);
-		return 1;
-	}
-
-	/* Hack to handle the one variable-size write command. See
-	   wavefront_send_multisample() for the other half of this
-	   gross and ugly strategy.
-	*/
-
-	if (cmd == WFC_DOWNLOAD_MULTISAMPLE) {
-		wfcmd->write_cnt = (unsigned int) rbuf;
-		rbuf = NULL;
-	}
-
-	DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n",
-			       cmd, wfcmd->action, wfcmd->read_cnt,
-			       wfcmd->write_cnt, wfcmd->need_ack);
-    
-	if (wavefront_write (cmd)) { 
-		DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request "
-						     "0x%x [%s].\n",
-						     cmd, wfcmd->action);
-		return 1;
-	} 
-
-	if (wfcmd->write_cnt > 0) {
-		DPRINT (WF_DEBUG_DATA, "writing %d bytes "
-					"for 0x%x\n",
-					wfcmd->write_cnt, cmd);
-
-		for (i = 0; i < wfcmd->write_cnt; i++) {
-			if (wavefront_write (wbuf[i])) {
-				DPRINT (WF_DEBUG_IO, "bad write for byte "
-						      "%d of 0x%x [%s].\n",
-						      i, cmd, wfcmd->action);
-				return 1;
-			}
-
-			DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n",
-						i, wbuf[i]);
-		}
-	}
-
-	if (wfcmd->read_cnt > 0) {
-		DPRINT (WF_DEBUG_DATA, "reading %d ints "
-					"for 0x%x\n",
-					wfcmd->read_cnt, cmd);
-
-		for (i = 0; i < wfcmd->read_cnt; i++) {
-
-			if ((c = wavefront_read()) == -1) {
-				DPRINT (WF_DEBUG_IO, "bad read for byte "
-						      "%d of 0x%x [%s].\n",
-						      i, cmd, wfcmd->action);
-				return 1;
-			}
-
-			/* Now handle errors. Lots of special cases here */
-	    
-			if (c == 0xff) { 
-				if ((c = wavefront_read ()) == -1) {
-					DPRINT (WF_DEBUG_IO, "bad read for "
-							      "error byte at "
-							      "read byte %d "
-							      "of 0x%x [%s].\n",
-							      i, cmd,
-							      wfcmd->action);
-					return 1;
-				}
-
-				/* Can you believe this madness ? */
-
-				if (c == 1 &&
-				    wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) {
-					rbuf[0] = WF_ST_EMPTY;
-					return (0);
-
-				} else if (c == 3 &&
-					   wfcmd->cmd == WFC_UPLOAD_PATCH) {
-
-					return 3;
-
-				} else if (c == 1 &&
-					   wfcmd->cmd == WFC_UPLOAD_PROGRAM) {
-
-					return 1;
-
-				} else {
-
-					DPRINT (WF_DEBUG_IO, "error %d (%s) "
-							      "during "
-							      "read for byte "
-							      "%d of 0x%x "
-							      "[%s].\n",
-							      c,
-							      wavefront_errorstr (c),
-							      i, cmd,
-							      wfcmd->action);
-					return 1;
-
-				}
-		
-		} else {
-				rbuf[i] = c;
-			}
-			
-			DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]);
-		}
-	}
-	
-	if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) {
-
-		DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd);
-
-		/* Some commands need an ACK, but return zero instead
-		   of the standard value.
-		*/
-	    
-		if ((ack = wavefront_read()) == 0) {
-			ack = WF_ACK;
-		}
-	
-		if (ack != WF_ACK) {
-			if (ack == -1) {
-				DPRINT (WF_DEBUG_IO, "cannot read ack for "
-						      "0x%x [%s].\n",
-						      cmd, wfcmd->action);
-				return 1;
-		
-			} else {
-				int err = -1; /* something unknown */
-
-				if (ack == 0xff) { /* explicit error */
-		    
-					if ((err = wavefront_read ()) == -1) {
-						DPRINT (WF_DEBUG_DATA,
-							"cannot read err "
-							"for 0x%x [%s].\n",
-							cmd, wfcmd->action);
-					}
-				}
-				
-				DPRINT (WF_DEBUG_IO, "0x%x [%s] "
-					"failed (0x%x, 0x%x, %s)\n",
-					cmd, wfcmd->action, ack, err,
-					wavefront_errorstr (err));
-				
-				return -err;
-			}
-		}
-		
-		DPRINT (WF_DEBUG_DATA, "ack received "
-					"for 0x%x [%s]\n",
-					cmd, wfcmd->action);
-	} else {
-
-		DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need "
-				       "ACK (%d,%d,%d)\n",
-				       cmd, wfcmd->action, wfcmd->read_cnt,
-				       wfcmd->write_cnt, wfcmd->need_ack);
-	}
-
-	return 0;
-	
-}
-
-/***********************************************************************
-WaveFront: data munging   
-
-Things here are weird. All data written to the board cannot 
-have its most significant bit set. Any data item with values 
-potentially > 0x7F (127) must be split across multiple bytes.
-
-Sometimes, we need to munge numeric values that are represented on
-the x86 side as 8-32 bit values. Sometimes, we need to munge data
-that is represented on the x86 side as an array of bytes. The most
-efficient approach to handling both cases seems to be to use 2
-different functions for munging and 2 for de-munging. This avoids
-weird casting and worrying about bit-level offsets.
-
-**********************************************************************/
-
-static 
-unsigned char *
-munge_int32 (unsigned int src,
-	     unsigned char *dst,
-	     unsigned int dst_size)
-{
-	int i;
-
-	for (i = 0;i < dst_size; i++) {
-		*dst = src & 0x7F;  /* Mask high bit of LSB */
-		src = src >> 7;     /* Rotate Right 7 bits  */
-	                            /* Note: we leave the upper bits in place */ 
-
-		dst++;
- 	};
-	return dst;
-};
-
-static int 
-demunge_int32 (unsigned char* src, int src_size)
-
-{
-	int i;
- 	int outval = 0;
-	
- 	for (i = src_size - 1; i >= 0; i--) {
-		outval=(outval<<7)+src[i];
-	}
-
-	return outval;
-};
-
-static 
-unsigned char *
-munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size)
-
-{
-	int i;
-	unsigned int last = dst_size / 2;
-
-	for (i = 0; i < last; i++) {
-		*dst++ = src[i] & 0x7f;
-		*dst++ = src[i] >> 7;
-	}
-	return dst;
-}
-
-static 
-unsigned char *
-demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes)
-
-{
-	int i;
-	unsigned char *end = src + src_bytes;
-    
-	end = src + src_bytes;
-
-	/* NOTE: src and dst *CAN* point to the same address */
-
-	for (i = 0; src != end; i++) {
-		dst[i] = *src++;
-		dst[i] |= (*src++)<<7;
-	}
-
-	return dst;
-}
-
-/***********************************************************************
-WaveFront: sample, patch and program management.
-***********************************************************************/
-
-static int
-wavefront_delete_sample (int sample_num)
-
-{
-	unsigned char wbuf[2];
-	int x;
-
-	wbuf[0] = sample_num & 0x7f;
-	wbuf[1] = sample_num >> 7;
-
-	if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) {
-		dev.sample_status[sample_num] = WF_ST_EMPTY;
-	}
-
-	return x;
-}
-
-static int
-wavefront_get_sample_status (int assume_rom)
-
-{
-	int i;
-	unsigned char rbuf[32], wbuf[32];
-	unsigned int    sc_real, sc_alias, sc_multi;
-
-	/* check sample status */
-    
-	if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) {
-		printk (KERN_WARNING LOGNAME "cannot request sample count.\n");
-		return -1;
-	} 
-    
-	sc_real = sc_alias = sc_multi = dev.samples_used = 0;
-    
-	for (i = 0; i < WF_MAX_SAMPLE; i++) {
-	
-		wbuf[0] = i & 0x7f;
-		wbuf[1] = i >> 7;
-
-		if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
-			printk (KERN_WARNING LOGNAME
-				"cannot identify sample "
-				"type of slot %d\n", i);
-			dev.sample_status[i] = WF_ST_EMPTY;
-			continue;
-		}
-
-		dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]);
-
-		if (assume_rom) {
-			dev.sample_status[i] |= WF_SLOT_ROM;
-		}
-
-		switch (rbuf[0] & WF_ST_MASK) {
-		case WF_ST_SAMPLE:
-			sc_real++;
-			break;
-		case WF_ST_MULTISAMPLE:
-			sc_multi++;
-			break;
-		case WF_ST_ALIAS:
-			sc_alias++;
-			break;
-		case WF_ST_EMPTY:
-			break;
-
-		default:
-			printk (KERN_WARNING LOGNAME "unknown sample type for "
-				"slot %d (0x%x)\n", 
-				i, rbuf[0]);
-		}
-
-		if (rbuf[0] != WF_ST_EMPTY) {
-			dev.samples_used++;
-		} 
-	}
-
-	printk (KERN_INFO LOGNAME
-		"%d samples used (%d real, %d aliases, %d multi), "
-		"%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi,
-		WF_MAX_SAMPLE - dev.samples_used);
-
-
-	return (0);
-
-}
-
-static int
-wavefront_get_patch_status (void)
-
-{
-	unsigned char patchbuf[WF_PATCH_BYTES];
-	unsigned char patchnum[2];
-	wavefront_patch *p;
-	int i, x, cnt, cnt2;
-
-	for (i = 0; i < WF_MAX_PATCH; i++) {
-		patchnum[0] = i & 0x7f;
-		patchnum[1] = i >> 7;
-
-		if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf,
-					patchnum)) == 0) {
-
-			dev.patch_status[i] |= WF_SLOT_FILLED;
-			p = (wavefront_patch *) patchbuf;
-			dev.sample_status
-				[p->sample_number|(p->sample_msb<<7)] |=
-				WF_SLOT_USED;
-	    
-		} else if (x == 3) { /* Bad patch number */
-			dev.patch_status[i] = 0;
-		} else {
-			printk (KERN_ERR LOGNAME "upload patch "
-				"error 0x%x\n", x);
-			dev.patch_status[i] = 0;
-			return 1;
-		}
-	}
-
-	/* program status has already filled in slot_used bits */
-
-	for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) {
-		if (dev.patch_status[i] & WF_SLOT_FILLED) {
-			cnt++;
-		}
-		if (dev.patch_status[i] & WF_SLOT_USED) {
-			cnt2++;
-		}
-	
-	}
-	printk (KERN_INFO LOGNAME
-		"%d patch slots filled, %d in use\n", cnt, cnt2);
-
-	return (0);
-}
-
-static int
-wavefront_get_program_status (void)
-
-{
-	unsigned char progbuf[WF_PROGRAM_BYTES];
-	wavefront_program prog;
-	unsigned char prognum;
-	int i, x, l, cnt;
-
-	for (i = 0; i < WF_MAX_PROGRAM; i++) {
-		prognum = i;
-
-		if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf,
-					&prognum)) == 0) {
-
-			dev.prog_status[i] |= WF_SLOT_USED;
-
-			demunge_buf (progbuf, (unsigned char *) &prog,
-				     WF_PROGRAM_BYTES);
-
-			for (l = 0; l < WF_NUM_LAYERS; l++) {
-				if (prog.layer[l].mute) {
-					dev.patch_status
-						[prog.layer[l].patch_number] |=
-						WF_SLOT_USED;
-				}
-			}
-		} else if (x == 1) { /* Bad program number */
-			dev.prog_status[i] = 0;
-		} else {
-			printk (KERN_ERR LOGNAME "upload program "
-				"error 0x%x\n", x);
-			dev.prog_status[i] = 0;
-		}
-	}
-
-	for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) {
-		if (dev.prog_status[i]) {
-			cnt++;
-		}
-	}
-
-	printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt);
-
-	return (0);
-}
-
-static int
-wavefront_send_patch (wavefront_patch_info *header)
-
-{
-	unsigned char buf[WF_PATCH_BYTES+2];
-	unsigned char *bptr;
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n",
-				      header->number);
-
-	dev.patch_status[header->number] |= WF_SLOT_FILLED;
-
-	bptr = buf;
-	bptr = munge_int32 (header->number, buf, 2);
-	munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES);
-    
-	if (wavefront_cmd (WFC_DOWNLOAD_PATCH, NULL, buf)) {
-		printk (KERN_ERR LOGNAME "download patch failed\n");
-		return -(EIO);
-	}
-
-	return (0);
-}
-
-static int
-wavefront_send_program (wavefront_patch_info *header)
-
-{
-	unsigned char buf[WF_PROGRAM_BYTES+1];
-	int i;
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n",
-		header->number);
-
-	dev.prog_status[header->number] = WF_SLOT_USED;
-
-	/* XXX need to zero existing SLOT_USED bit for program_status[i]
-	   where `i' is the program that's being (potentially) overwritten.
-	*/
-    
-	for (i = 0; i < WF_NUM_LAYERS; i++) {
-		if (header->hdr.pr.layer[i].mute) {
-			dev.patch_status[header->hdr.pr.layer[i].patch_number] |=
-				WF_SLOT_USED;
-
-			/* XXX need to mark SLOT_USED for sample used by
-			   patch_number, but this means we have to load it. Ick.
-			*/
-		}
-	}
-
-	buf[0] = header->number;
-	munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES);
-    
-	if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, NULL, buf)) {
-		printk (KERN_WARNING LOGNAME "download patch failed\n");	
-		return -(EIO);
-	}
-
-	return (0);
-}
-
-static int
-wavefront_freemem (void)
-
-{
-	char rbuf[8];
-
-	if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, NULL)) {
-		printk (KERN_WARNING LOGNAME "can't get memory stats.\n");
-		return -1;
-	} else {
-		return demunge_int32 (rbuf, 4);
-	}
-}
-
-static int
-wavefront_send_sample (wavefront_patch_info *header,
-		       UINT16 __user *dataptr,
-		       int data_is_unsigned)
-
-{
-	/* samples are downloaded via a 16-bit wide i/o port
-	   (you could think of it as 2 adjacent 8-bit wide ports
-	   but its less efficient that way). therefore, all
-	   the blocksizes and so forth listed in the documentation,
-	   and used conventionally to refer to sample sizes,
-	   which are given in 8-bit units (bytes), need to be
-	   divided by 2.
-        */
-
-	UINT16 sample_short;
-	UINT32 length;
-	UINT16 __user *data_end = NULL;
-	unsigned int i;
-	const int max_blksize = 4096/2;
-	unsigned int written;
-	unsigned int blocksize;
-	int dma_ack;
-	int blocknum;
-	unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES];
-	unsigned char *shptr;
-	int skip = 0;
-	int initial_skip = 0;
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, "
-				      "type %d, %d bytes from %p\n",
-				      header->size ? "" : "header ", 
-				      header->number, header->subkey,
-				      header->size,
-				      header->dataptr);
-
-	if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) {
-		int x;
-
-		if ((x = wavefront_find_free_sample ()) < 0) {
-			return -ENOMEM;
-		}
-		printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x);
-		header->number = x;
-	}
-
-	if (header->size) {
-
-		/* XXX it's a debatable point whether or not RDONLY semantics
-		   on the ROM samples should cover just the sample data or
-		   the sample header. For now, it only covers the sample data,
-		   so anyone is free at all times to rewrite sample headers.
-
-		   My reason for this is that we have the sample headers
-		   available in the WFB file for General MIDI, and so these
-		   can always be reset if needed. The sample data, however,
-		   cannot be recovered without a complete reset and firmware
-		   reload of the ICS2115, which is a very expensive operation.
-
-		   So, doing things this way allows us to honor the notion of
-		   "RESETSAMPLES" reasonably cheaply. Note however, that this
-		   is done purely at user level: there is no WFB parser in
-		   this driver, and so a complete reset (back to General MIDI,
-		   or theoretically some other configuration) is the
-		   responsibility of the user level library. 
-
-		   To try to do this in the kernel would be a little
-		   crazy: we'd need 158K of kernel space just to hold
-		   a copy of the patch/program/sample header data.
-		*/
-
-		if (dev.rom_samples_rdonly) {
-			if (dev.sample_status[header->number] & WF_SLOT_ROM) {
-				printk (KERN_ERR LOGNAME "sample slot %d "
-					"write protected\n",
-					header->number);
-				return -EACCES;
-			}
-		}
-
-		wavefront_delete_sample (header->number);
-	}
-
-	if (header->size) {
-		dev.freemem = wavefront_freemem ();
-
-		if (dev.freemem < header->size) {
-			printk (KERN_ERR LOGNAME
-				"insufficient memory to "
-				"load %d byte sample.\n",
-				header->size);
-			return -ENOMEM;
-		}
-	
-	}
-
-	skip = WF_GET_CHANNEL(&header->hdr.s);
-
-	if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
-		printk (KERN_ERR LOGNAME "channel selection only "
-			"possible on 16-bit samples");
-		return -(EINVAL);
-	}
-
-	switch (skip) {
-	case 0:
-		initial_skip = 0;
-		skip = 1;
-		break;
-	case 1:
-		initial_skip = 0;
-		skip = 2;
-		break;
-	case 2:
-		initial_skip = 1;
-		skip = 2;
-		break;
-	case 3:
-		initial_skip = 2;
-		skip = 3;
-		break;
-	case 4:
-		initial_skip = 3;
-		skip = 4;
-		break;
-	case 5:
-		initial_skip = 4;
-		skip = 5;
-		break;
-	case 6:
-		initial_skip = 5;
-		skip = 6;
-		break;
-	}
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => "
-				      "initial skip = %d, skip = %d\n",
-				      WF_GET_CHANNEL (&header->hdr.s),
-				      initial_skip, skip);
-    
-	/* Be safe, and zero the "Unused" bits ... */
-
-	WF_SET_CHANNEL(&header->hdr.s, 0);
-
-	/* adjust size for 16 bit samples by dividing by two.  We always
-	   send 16 bits per write, even for 8 bit samples, so the length
-	   is always half the size of the sample data in bytes.
-	*/
-
-	length = header->size / 2;
-
-	/* the data we're sent has not been munged, and in fact, the
-	   header we have to send isn't just a munged copy either.
-	   so, build the sample header right here.
-	*/
-
-	shptr = &sample_hdr[0];
-
-	shptr = munge_int32 (header->number, shptr, 2);
-
-	if (header->size) {
-		shptr = munge_int32 (length, shptr, 4);
-	}
-
-	/* Yes, a 4 byte result doesn't contain all of the offset bits,
-	   but the offset only uses 24 bits.
-	*/
-
-	shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset),
-			     shptr, 4);
-	shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset),
-			     shptr, 4);
-	shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset),
-			     shptr, 4);
-	shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset),
-			     shptr, 4);
-	
-	/* This one is truly weird. What kind of weirdo decided that in
-	   a system dominated by 16 and 32 bit integers, they would use
-	   a just 12 bits ?
-	*/
-	
-	shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3);
-	
-	/* Why is this nybblified, when the MSB is *always* zero ? 
-	   Anyway, we can't take address of bitfield, so make a
-	   good-faith guess at where it starts.
-	*/
-	
-	shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1),
-			     shptr, 2);
-
-	if (wavefront_cmd (header->size ?
-			   WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER,
-			   NULL, sample_hdr)) {
-		printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n",
-			header->size ? "" : "header ");
-		return -(EIO);
-	}
-
-	if (header->size == 0) {
-		goto sent; /* Sorry. Just had to have one somewhere */
-	}
-    
-	data_end = dataptr + length;
-
-	/* Do any initial skip over an unused channel's data */
-
-	dataptr += initial_skip;
-    
-	for (written = 0, blocknum = 0;
-	     written < length; written += max_blksize, blocknum++) {
-	
-		if ((length - written) > max_blksize) {
-			blocksize = max_blksize;
-		} else {
-			/* round to nearest 16-byte value */
-			blocksize = ((length-written+7)&~0x7);
-		}
-
-		if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
-			printk (KERN_WARNING LOGNAME "download block "
-				"request refused.\n");
-			return -(EIO);
-		}
-
-		for (i = 0; i < blocksize; i++) {
-
-			if (dataptr < data_end) {
-		
-				__get_user (sample_short, dataptr);
-				dataptr += skip;
-		
-				if (data_is_unsigned) { /* GUS ? */
-
-					if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) {
-			
-						/* 8 bit sample
-						 resolution, sign
-						 extend both bytes.
-						*/
-			
-						((unsigned char*)
-						 &sample_short)[0] += 0x7f;
-						((unsigned char*)
-						 &sample_short)[1] += 0x7f;
-			
-					} else {
-			
-						/* 16 bit sample
-						 resolution, sign
-						 extend the MSB.
-						*/
-			
-						sample_short += 0x7fff;
-					}
-				}
-
-			} else {
-
-				/* In padding section of final block:
-
-				   Don't fetch unsupplied data from
-				   user space, just continue with
-				   whatever the final value was.
-				*/
-			}
-	    
-			if (i < blocksize - 1) {
-				outw (sample_short, dev.block_port);
-			} else {
-				outw (sample_short, dev.last_block_port);
-			}
-		}
-
-		/* Get "DMA page acknowledge", even though its really
-		   nothing to do with DMA at all.
-		*/
-	
-		if ((dma_ack = wavefront_read ()) != WF_DMA_ACK) {
-			if (dma_ack == -1) {
-				printk (KERN_ERR LOGNAME "upload sample "
-					"DMA ack timeout\n");
-				return -(EIO);
-			} else {
-				printk (KERN_ERR LOGNAME "upload sample "
-					"DMA ack error 0x%x\n",
-					dma_ack);
-				return -(EIO);
-			}
-		}
-	}
-
-	dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE);
-
-	/* Note, label is here because sending the sample header shouldn't
-	   alter the sample_status info at all.
-	*/
-
- sent:
-	return (0);
-}
-
-static int
-wavefront_send_alias (wavefront_patch_info *header)
-
-{
-	unsigned char alias_hdr[WF_ALIAS_BYTES];
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is "
-				      "alias for %d\n",
-				      header->number,
-				      header->hdr.a.OriginalSample);
-    
-	munge_int32 (header->number, &alias_hdr[0], 2);
-	munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2);
-	munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset),
-		     &alias_hdr[4], 4);
-	munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset),
-		     &alias_hdr[8], 4);
-	munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset),
-		     &alias_hdr[12], 4);
-	munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset),
-		     &alias_hdr[16], 4);
-	munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3);
-	munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2);
-
-	if (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) {
-		printk (KERN_ERR LOGNAME "download alias failed.\n");
-		return -(EIO);
-	}
-
-	dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
-
-	return (0);
-}
-
-static int
-wavefront_send_multisample (wavefront_patch_info *header)
-{
-	int i;
-	int num_samples;
-	unsigned char msample_hdr[WF_MSAMPLE_BYTES];
-
-	munge_int32 (header->number, &msample_hdr[0], 2);
-
-	/* You'll recall at this point that the "number of samples" value
-	   in a wavefront_multisample struct is actually the log2 of the
-	   real number of samples.
-	*/
-
-	num_samples = (1<<(header->hdr.ms.NumberOfSamples&7));
-	msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples;
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n",
-				      header->number,
-				      header->hdr.ms.NumberOfSamples,
-				      num_samples);
-
-	for (i = 0; i < num_samples; i++) {
-		DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n",
-		       i, header->hdr.ms.SampleNumber[i]);
-		munge_int32 (header->hdr.ms.SampleNumber[i],
-		     &msample_hdr[3+(i*2)], 2);
-	}
-    
-	/* Need a hack here to pass in the number of bytes
-	   to be written to the synth. This is ugly, and perhaps
-	   one day, I'll fix it.
-	*/
-
-	if (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE, 
-			   (unsigned char *) ((num_samples*2)+3),
-			   msample_hdr)) {
-		printk (KERN_ERR LOGNAME "download of multisample failed.\n");
-		return -(EIO);
-	}
-
-	dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
-
-	return (0);
-}
-
-static int
-wavefront_fetch_multisample (wavefront_patch_info *header)
-{
-	int i;
-	unsigned char log_ns[1];
-	unsigned char number[2];
-	int num_samples;
-
-	munge_int32 (header->number, number, 2);
-    
-	if (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
-		printk (KERN_ERR LOGNAME "upload multisample failed.\n");
-		return -(EIO);
-	}
-    
-	DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n",
-				header->number, log_ns[0]);
-
-	header->hdr.ms.NumberOfSamples = log_ns[0];
-
-	/* get the number of samples ... */
-
-	num_samples = (1 << log_ns[0]);
-    
-	for (i = 0; i < num_samples; i++) {
-		s8 d[2];
-	
-		if ((d[0] = wavefront_read ()) == -1) {
-			printk (KERN_ERR LOGNAME "upload multisample failed "
-				"during sample loop.\n");
-			return -(EIO);
-		}
-
-		if ((d[1] = wavefront_read ()) == -1) {
-			printk (KERN_ERR LOGNAME "upload multisample failed "
-				"during sample loop.\n");
-			return -(EIO);
-		}
-	
-		header->hdr.ms.SampleNumber[i] =
-			demunge_int32 ((unsigned char *) d, 2);
-	
-		DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n",
-					i, header->hdr.ms.SampleNumber[i]);
-	}
-
-	return (0);
-}
-
-
-static int
-wavefront_send_drum (wavefront_patch_info *header)
-
-{
-	unsigned char drumbuf[WF_DRUM_BYTES];
-	wavefront_drum *drum = &header->hdr.d;
-	int i;
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI "
-		"note %d, patch = %d\n", 
-		header->number, drum->PatchNumber);
-
-	drumbuf[0] = header->number & 0x7f;
-
-	for (i = 0; i < 4; i++) {
-		munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2);
-	}
-
-	if (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) {
-		printk (KERN_ERR LOGNAME "download drum failed.\n");
-		return -(EIO);
-	}
-
-	return (0);
-}
-
-static int 
-wavefront_find_free_sample (void)
-
-{
-	int i;
-
-	for (i = 0; i < WF_MAX_SAMPLE; i++) {
-		if (!(dev.sample_status[i] & WF_SLOT_FILLED)) {
-			return i;
-		}
-	}
-	printk (KERN_WARNING LOGNAME "no free sample slots!\n");
-	return -1;
-}
-
-static int 
-wavefront_find_free_patch (void)
-
-{
-	int i;
-
-	for (i = 0; i < WF_MAX_PATCH; i++) {
-		if (!(dev.patch_status[i] & WF_SLOT_FILLED)) {
-			return i;
-		}
-	}
-	printk (KERN_WARNING LOGNAME "no free patch slots!\n");
-	return -1;
-}
-
-static int 
-log2_2048(int n)
-
-{
-	int tbl[]={0, 0, 2048, 3246, 4096, 4755, 5294, 5749, 6143,
-		   6492, 6803, 7084, 7342, 7578, 7797, 8001, 8192,
-		   8371, 8540, 8699, 8851, 8995, 9132, 9264, 9390,
-		   9510, 9626, 9738, 9845, 9949, 10049, 10146};
-	int i;
-
-	/* Returns 2048*log2(n) */
-
-	/* FIXME: this is like doing integer math
-	   on quantum particles (RuN) */
-
-	i=0;
-	while(n>=32*256) {
-		n>>=8;
-		i+=2048*8;
-	}
-	while(n>=32) {
-		n>>=1;
-		i+=2048;
-	}
-	i+=tbl[n];
-	return(i);
-}
-
-static int
-wavefront_load_gus_patch (int devno, int format, const char __user *addr,
-			  int offs, int count, int pmgr_flag)
-{
-	struct patch_info guspatch;
-	wavefront_patch_info *samp, *pat, *prog;
-	wavefront_patch *patp;
-	wavefront_sample *sampp;
-	wavefront_program *progp;
-
-	int i,base_note;
-	long sizeof_patch;
-	int rc = -ENOMEM;
-
-	samp = kmalloc(3 * sizeof(wavefront_patch_info), GFP_KERNEL);
-	if (!samp)
-		goto free_fail;
-	pat = samp + 1;
-	prog = pat + 1;
-
-	/* Copy in the header of the GUS patch */
-
-	sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch; 
-	if (copy_from_user(&((char *) &guspatch)[offs],
-			   &(addr)[offs], sizeof_patch - offs)) {
-		rc = -EFAULT;
-		goto free_fail;
-	}
-
-	if ((i = wavefront_find_free_patch ()) == -1) {
-		rc = -EBUSY;
-		goto free_fail;
-	}
-	pat->number = i;
-	pat->subkey = WF_ST_PATCH;
-	patp = &pat->hdr.p;
-
-	if ((i = wavefront_find_free_sample ()) == -1) {
-		rc = -EBUSY;
-		goto free_fail;
-	}
-	samp->number = i;
-	samp->subkey = WF_ST_SAMPLE;
-	samp->size = guspatch.len;
-	sampp = &samp->hdr.s;
-
-	prog->number = guspatch.instr_no;
-	progp = &prog->hdr.pr;
-
-	/* Setup the patch structure */
-
-	patp->amplitude_bias=guspatch.volume;
-	patp->portamento=0;
-	patp->sample_number= samp->number & 0xff;
-	patp->sample_msb= samp->number >> 8;
-	patp->pitch_bend= /*12*/ 0;
-	patp->mono=1;
-	patp->retrigger=1;
-	patp->nohold=(guspatch.mode & WAVE_SUSTAIN_ON) ? 0:1;
-	patp->frequency_bias=0;
-	patp->restart=0;
-	patp->reuse=0;
-	patp->reset_lfo=1;
-	patp->fm_src2=0;
-	patp->fm_src1=WF_MOD_MOD_WHEEL;
-	patp->am_src=WF_MOD_PRESSURE;
-	patp->am_amount=127;
-	patp->fc1_mod_amount=0;
-	patp->fc2_mod_amount=0; 
-	patp->fm_amount1=0;
-	patp->fm_amount2=0;
-	patp->envelope1.attack_level=127;
-	patp->envelope1.decay1_level=127;
-	patp->envelope1.decay2_level=127;
-	patp->envelope1.sustain_level=127;
-	patp->envelope1.release_level=0;
-	patp->envelope2.attack_velocity=127;
-	patp->envelope2.attack_level=127;
-	patp->envelope2.decay1_level=127;
-	patp->envelope2.decay2_level=127;
-	patp->envelope2.sustain_level=127;
-	patp->envelope2.release_level=0;
-	patp->envelope2.attack_velocity=127;
-	patp->randomizer=0;
-
-	/* Program for this patch */
-
-	progp->layer[0].patch_number= pat->number; /* XXX is this right ? */
-	progp->layer[0].mute=1;
-	progp->layer[0].pan_or_mod=1;
-	progp->layer[0].pan=7;
-	progp->layer[0].mix_level=127  /* guspatch.volume */;
-	progp->layer[0].split_type=0;
-	progp->layer[0].split_point=0;
-	progp->layer[0].play_below=0;
-
-	for (i = 1; i < 4; i++) {
-		progp->layer[i].mute=0;
-	}
-
-	/* Sample data */
-
-	sampp->SampleResolution=((~guspatch.mode & WAVE_16_BITS)<<1);
-
-	for (base_note=0;
-	     note_to_freq (base_note) < guspatch.base_note;
-	     base_note++);
-
-	if ((guspatch.base_note-note_to_freq(base_note))
-	    >(note_to_freq(base_note)-guspatch.base_note))
-		base_note++;
-
-	printk(KERN_DEBUG "ref freq=%d,base note=%d\n",
-	       guspatch.base_freq,
-	       base_note);
-
-	sampp->FrequencyBias = (29550 - log2_2048(guspatch.base_freq)
-				+ base_note*171);
-	printk(KERN_DEBUG "Freq Bias is %d\n", sampp->FrequencyBias);
-	sampp->Loop=(guspatch.mode & WAVE_LOOPING) ? 1:0;
-	sampp->sampleStartOffset.Fraction=0;
-	sampp->sampleStartOffset.Integer=0;
-	sampp->loopStartOffset.Fraction=0;
-	sampp->loopStartOffset.Integer=guspatch.loop_start
-		>>((guspatch.mode&WAVE_16_BITS) ? 1:0);
-	sampp->loopEndOffset.Fraction=0;
-	sampp->loopEndOffset.Integer=guspatch.loop_end
-		>>((guspatch.mode&WAVE_16_BITS) ? 1:0);
-	sampp->sampleEndOffset.Fraction=0;
-	sampp->sampleEndOffset.Integer=guspatch.len >> (guspatch.mode&1);
-	sampp->Bidirectional=(guspatch.mode&WAVE_BIDIR_LOOP) ? 1:0;
-	sampp->Reverse=(guspatch.mode&WAVE_LOOP_BACK) ? 1:0;
-
-	/* Now ship it down */
-
-	wavefront_send_sample (samp,
-			       (unsigned short __user *) &(addr)[sizeof_patch],
-			       (guspatch.mode & WAVE_UNSIGNED) ? 1:0);
-	wavefront_send_patch (pat);
-	wavefront_send_program (prog);
-
-	/* Now pan as best we can ... use the slave/internal MIDI device
-	   number if it exists (since it talks to the WaveFront), or the
-	   master otherwise.
-	*/
-
-	if (dev.mididev > 0) {
-		midi_synth_controller (dev.mididev, guspatch.instr_no, 10,
-				       ((guspatch.panning << 4) > 127) ?
-				       127 : (guspatch.panning << 4));
-	}
-	rc = 0;
-
-free_fail:
-	kfree(samp);
-	return rc;
-}
-
-static int
-wavefront_load_patch (const char __user *addr)
-
-
-{
-	wavefront_patch_info header;
-	
-	if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) -
-			    sizeof(wavefront_any))) {
-		printk (KERN_WARNING LOGNAME "bad address for load patch.\n");
-		return -EFAULT;
-	}
-
-	DPRINT (WF_DEBUG_LOAD_PATCH, "download "
-				      "Sample type: %d "
-				      "Sample number: %d "
-				      "Sample size: %d\n",
-				      header.subkey,
-				      header.number,
-				      header.size);
-
-	switch (header.subkey) {
-	case WF_ST_SAMPLE:  /* sample or sample_header, based on patch->size */
-
-		if (copy_from_user((unsigned char *) &header.hdr.s,
-				   (unsigned char __user *) header.hdrptr,
-				   sizeof (wavefront_sample)))
-			return -EFAULT;
-
-		return wavefront_send_sample (&header, header.dataptr, 0);
-
-	case WF_ST_MULTISAMPLE:
-
-		if (copy_from_user(&header.hdr.s, header.hdrptr,
-				   sizeof(wavefront_multisample)))
-			return -EFAULT;
-
-		return wavefront_send_multisample (&header);
-
-
-	case WF_ST_ALIAS:
-
-		if (copy_from_user(&header.hdr.a, header.hdrptr,
-				   sizeof (wavefront_alias)))
-			return -EFAULT;
-
-		return wavefront_send_alias (&header);
-
-	case WF_ST_DRUM:
-		if (copy_from_user(&header.hdr.d, header.hdrptr,
-				   sizeof (wavefront_drum)))
-			return -EFAULT;
-
-		return wavefront_send_drum (&header);
-
-	case WF_ST_PATCH:
-		if (copy_from_user(&header.hdr.p, header.hdrptr,
-				   sizeof (wavefront_patch)))
-			return -EFAULT;
-
-		return wavefront_send_patch (&header);
-
-	case WF_ST_PROGRAM:
-		if (copy_from_user(&header.hdr.pr, header.hdrptr,
-				   sizeof (wavefront_program)))
-			return -EFAULT;
-
-		return wavefront_send_program (&header);
-
-	default:
-		printk (KERN_ERR LOGNAME "unknown patch type %d.\n",
-			header.subkey);
-		return -(EINVAL);
-	}
-
-	return 0;
-}
-
-/***********************************************************************
-WaveFront: /dev/sequencer{,2} and other hardware-dependent interfaces
-***********************************************************************/
-
-static void
-process_sample_hdr (UCHAR8 *buf)
-
-{
-	wavefront_sample s;
-	UCHAR8 *ptr;
-
-	ptr = buf;
-
-	/* The board doesn't send us an exact copy of a "wavefront_sample"
-	   in response to an Upload Sample Header command. Instead, we 
-	   have to convert the data format back into our data structure,
-	   just as in the Download Sample command, where we have to do
-	   something very similar in the reverse direction.
-	*/
-
-	*((UINT32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
-	*((UINT32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
-	*((UINT32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
-	*((UINT32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
-	*((UINT32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3;
-
-	s.SampleResolution = *ptr & 0x3;
-	s.Loop = *ptr & 0x8;
-	s.Bidirectional = *ptr & 0x10;
-	s.Reverse = *ptr & 0x40;
-
-	/* Now copy it back to where it came from */
-
-	memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample));
-}
-
-static int
-wavefront_synth_control (int cmd, wavefront_control *wc)
-
-{
-	unsigned char patchnumbuf[2];
-	int i;
-
-	DPRINT (WF_DEBUG_CMD, "synth control with "
-		"cmd 0x%x\n", wc->cmd);
-
-	/* Pre-handling of or for various commands */
-
-	switch (wc->cmd) {
-	case WFC_DISABLE_INTERRUPTS:
-		printk (KERN_INFO LOGNAME "interrupts disabled.\n");
-		outb (0x80|0x20, dev.control_port);
-		dev.interrupts_on = 0;
-		return 0;
-
-	case WFC_ENABLE_INTERRUPTS:
-		printk (KERN_INFO LOGNAME "interrupts enabled.\n");
-		outb (0x80|0x40|0x20, dev.control_port);
-		dev.interrupts_on = 1;
-		return 0;
-
-	case WFC_INTERRUPT_STATUS:
-		wc->rbuf[0] = dev.interrupts_on;
-		return 0;
-
-	case WFC_ROMSAMPLES_RDONLY:
-		dev.rom_samples_rdonly = wc->wbuf[0];
-		wc->status = 0;
-		return 0;
-
-	case WFC_IDENTIFY_SLOT_TYPE:
-		i = wc->wbuf[0] | (wc->wbuf[1] << 7);
-		if (i <0 || i >= WF_MAX_SAMPLE) {
-			printk (KERN_WARNING LOGNAME "invalid slot ID %d\n",
-				i);
-			wc->status = EINVAL;
-			return 0;
-		}
-		wc->rbuf[0] = dev.sample_status[i];
-		wc->status = 0;
-		return 0;
-
-	case WFC_DEBUG_DRIVER:
-		dev.debug = wc->wbuf[0];
-		printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug);
-		return 0;
-
-	case WFC_FX_IOCTL:
-		wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]);
-		return 0;
-
-	case WFC_UPLOAD_PATCH:
-		munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2);
-		memcpy (wc->wbuf, patchnumbuf, 2);
-		break;
-
-	case WFC_UPLOAD_MULTISAMPLE:
-		/* multisamples have to be handled differently, and
-		   cannot be dealt with properly by wavefront_cmd() alone.
-		*/
-		wc->status = wavefront_fetch_multisample
-			((wavefront_patch_info *) wc->rbuf);
-		return 0;
-
-	case WFC_UPLOAD_SAMPLE_ALIAS:
-		printk (KERN_INFO LOGNAME "support for sample alias upload "
-			"being considered.\n");
-		wc->status = EINVAL;
-		return -EINVAL;
-	}
-
-	wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf);
-
-	/* Post-handling of certain commands.
-
-	   In particular, if the command was an upload, demunge the data
-	   so that the user-level doesn't have to think about it.
-	*/
-
-	if (wc->status == 0) {
-		switch (wc->cmd) {
-			/* intercept any freemem requests so that we know
-			   we are always current with the user-level view
-			   of things.
-			*/
-
-		case WFC_REPORT_FREE_MEMORY:
-			dev.freemem = demunge_int32 (wc->rbuf, 4);
-			break;
-
-		case WFC_UPLOAD_PATCH:
-			demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES);
-			break;
-
-		case WFC_UPLOAD_PROGRAM:
-			demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES);
-			break;
-
-		case WFC_UPLOAD_EDRUM_PROGRAM:
-			demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1);
-			break;
-
-		case WFC_UPLOAD_SAMPLE_HEADER:
-			process_sample_hdr (wc->rbuf);
-			break;
-
-		case WFC_UPLOAD_SAMPLE_ALIAS:
-			printk (KERN_INFO LOGNAME "support for "
-				"sample aliases still "
-				"being considered.\n");
-			break;
-
-		case WFC_VMIDI_OFF:
-			if (virtual_midi_disable () < 0) {
-				return -(EIO);
-			}
-			break;
-
-		case WFC_VMIDI_ON:
-			if (virtual_midi_enable () < 0) {
-				return -(EIO);
-			}
-			break;
-		}
-	}
-
-	return 0;
-}
-
-
-/***********************************************************************/
-/* WaveFront: Linux file system interface (for access via raw synth)    */
-/***********************************************************************/
-
-static int 
-wavefront_open (struct inode *inode, struct file *file)
-{
-	/* XXX fix me */
-	dev.opened = file->f_flags;
-	return 0;
-}
-
-static int
-wavefront_release(struct inode *inode, struct file *file)
-{
-	lock_kernel();
-	dev.opened = 0;
-	dev.debug = 0;
-	unlock_kernel();
-	return 0;
-}
-
-static int
-wavefront_ioctl(struct inode *inode, struct file *file,
-		unsigned int cmd, unsigned long arg)
-{
-	wavefront_control wc;
-	int err;
-
-	switch (cmd) {
-
-	case WFCTL_WFCMD:
-		if (copy_from_user(&wc, (void __user *) arg, sizeof (wc)))
-			return -EFAULT;
-		
-		if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
-			if (copy_to_user ((void __user *) arg, &wc, sizeof (wc)))
-				return -EFAULT;
-		}
-
-		return err;
-		
-	case WFCTL_LOAD_SPP:
-		return wavefront_load_patch ((const char __user *) arg);
-		
-	default:
-		printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd);
-		return -(EINVAL);
-
-	}
-	return 0;
-}
-
-static /*const*/ struct file_operations wavefront_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= wavefront_ioctl,
-	.open		= wavefront_open,
-	.release	= wavefront_release,
-};
-
-
-/***********************************************************************/
-/* WaveFront: OSS installation and support interface                   */
-/***********************************************************************/
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-
-static struct synth_info wavefront_info =
-{"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT,
- 0, 32, 0, 0, SYNTH_CAP_INPUT};
-
-static int
-wavefront_oss_open (int devno, int mode)
-
-{
-	dev.opened = mode;
-	return 0;
-}
-
-static void
-wavefront_oss_close (int devno)
-
-{
-	dev.opened = 0;
-	dev.debug = 0;
-	return;
-}
-
-static int
-wavefront_oss_ioctl (int devno, unsigned int cmd, void __user * arg)
-
-{
-	wavefront_control wc;
-	int err;
-
-	switch (cmd) {
-	case SNDCTL_SYNTH_INFO:
-		if(copy_to_user(arg, &wavefront_info, sizeof (wavefront_info)))
-			return -EFAULT;
-		return 0;
-
-	case SNDCTL_SEQ_RESETSAMPLES:
-//		printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
-		return 0; /* don't force an error */
-
-	case SNDCTL_SEQ_PERCMODE:
-		return 0; /* don't force an error */
-
-	case SNDCTL_SYNTH_MEMAVL:
-		if ((dev.freemem = wavefront_freemem ()) < 0) {
-			printk (KERN_ERR LOGNAME "cannot get memory size\n");
-			return -EIO;
-		} else {
-			return dev.freemem;
-		}
-		break;
-
-	case SNDCTL_SYNTH_CONTROL:
-		if(copy_from_user (&wc, arg, sizeof (wc)))
-			err = -EFAULT;
-		else if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
-			if(copy_to_user (arg, &wc, sizeof (wc)))
-				err = -EFAULT;
-		}
-
-		return err;
-
-	default:
-		return -(EINVAL);
-	}
-}
-
-static int
-wavefront_oss_load_patch (int devno, int format, const char __user *addr,
-			  int offs, int count, int pmgr_flag)
-{
-
-	if (format == SYSEX_PATCH) {	/* Handled by midi_synth.c */
-		if (midi_load_patch == NULL) {
-			printk (KERN_ERR LOGNAME
-				"SYSEX not loadable: "
-				"no midi patch loader!\n");
-			return -(EINVAL);
-		}
-
-		return midi_load_patch (devno, format, addr,
-					offs, count, pmgr_flag);
-
-	} else if (format == GUS_PATCH) {
-		return wavefront_load_gus_patch (devno, format,
-						 addr, offs, count, pmgr_flag);
-
-	} else if (format != WAVEFRONT_PATCH) {
-		printk (KERN_ERR LOGNAME "unknown patch format %d\n", format);
-		return -(EINVAL);
-	}
-
-	if (count < sizeof (wavefront_patch_info)) {
-		printk (KERN_ERR LOGNAME "sample header too short\n");
-		return -(EINVAL);
-	}
-
-	/* "addr" points to a user-space wavefront_patch_info */
-
-	return wavefront_load_patch (addr);
-}	
-
-static struct synth_operations wavefront_operations =
-{
-	.owner		= THIS_MODULE,
-	.id		= "WaveFront",
-	.info		= &wavefront_info,
-	.midi_dev	= 0,
-	.synth_type	= SYNTH_TYPE_SAMPLE,
-	.synth_subtype	= SAMPLE_TYPE_WAVEFRONT,
-	.open		= wavefront_oss_open,
-	.close		= wavefront_oss_close,
-	.ioctl		= wavefront_oss_ioctl,
-	.kill_note	= midi_synth_kill_note,
-	.start_note	= midi_synth_start_note,
-	.set_instr	= midi_synth_set_instr,
-	.reset		= midi_synth_reset,
-	.load_patch	= midi_synth_load_patch,
-	.aftertouch	= midi_synth_aftertouch,
-	.controller	= midi_synth_controller,
-	.panning	= midi_synth_panning,
-	.bender		= midi_synth_bender,
-	.setup_voice	= midi_synth_setup_voice
-};
-#endif /* OSS_SUPPORT_SEQ */
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL
-
-static void __init attach_wavefront (struct address_info *hw_config)
-{
-    (void) install_wavefront ();
-}
-
-static int __init probe_wavefront (struct address_info *hw_config)
-{
-    return !detect_wavefront (hw_config->irq, hw_config->io_base);
-}
-
-static void __exit unload_wavefront (struct address_info *hw_config) 
-{
-    (void) uninstall_wavefront ();
-}
-
-#endif /* OSS_SUPPORT_STATIC_INSTALL */
-
-/***********************************************************************/
-/* WaveFront: Linux modular sound kernel installation interface        */
-/***********************************************************************/
-
-static irqreturn_t
-wavefrontintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
-	struct wf_config *hw = dev_id;
-
-	/*
-	   Some comments on interrupts. I attempted a version of this
-	   driver that used interrupts throughout the code instead of
-	   doing busy and/or sleep-waiting. Alas, it appears that once
-	   the Motorola firmware is downloaded, the card *never*
-	   generates an RX interrupt. These are successfully generated
-	   during firmware loading, and after that wavefront_status()
-	   reports that an interrupt is pending on the card from time
-	   to time, but it never seems to be delivered to this
-	   driver. Note also that wavefront_status() continues to
-	   report that RX interrupts are enabled, suggesting that I
-	   didn't goof up and disable them by mistake.
-
-	   Thus, I stepped back to a prior version of
-	   wavefront_wait(), the only place where this really
-	   matters. Its sad, but I've looked through the code to check
-	   on things, and I really feel certain that the Motorola
-	   firmware prevents RX-ready interrupts.
-	*/
-
-	if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) {
-		return IRQ_NONE;
-	}
-
-	hw->irq_ok = 1;
-	hw->irq_cnt++;
-	wake_up_interruptible (&hw->interrupt_sleeper);
-	return IRQ_HANDLED;
-}
-
-/* STATUS REGISTER 
-
-0 Host Rx Interrupt Enable (1=Enabled)
-1 Host Rx Register Full (1=Full)
-2 Host Rx Interrupt Pending (1=Interrupt)
-3 Unused
-4 Host Tx Interrupt (1=Enabled)
-5 Host Tx Register empty (1=Empty)
-6 Host Tx Interrupt Pending (1=Interrupt)
-7 Unused
-*/
-
-static int
-wavefront_interrupt_bits (int irq)
-
-{
-	int bits;
-
-	switch (irq) {
-	case 9:
-		bits = 0x00;
-		break;
-	case 5:
-		bits = 0x08;
-		break;
-	case 12:
-		bits = 0x10;
-		break;
-	case 15:
-		bits = 0x18;
-		break;
-	
-	default:
-		printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq);
-		bits = -1;
-	}
-
-	return bits;
-}
-
-static void
-wavefront_should_cause_interrupt (int val, int port, int timeout)
-
-{
-	unsigned long flags;
-
-	/* this will not help on SMP - but at least it compiles */
-	spin_lock_irqsave(&lock, flags);
-	dev.irq_ok = 0;
-	outb (val,port);
-	interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout);
-	spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init wavefront_hw_reset (void)
-{
-	int bits;
-	int hwv[2];
-	unsigned long irq_mask;
-	short reported_irq;
-
-	/* IRQ already checked in init_module() */
-
-	bits = wavefront_interrupt_bits (dev.irq);
-
-	printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n");
-
-	irq_mask = probe_irq_on ();
-
-	outb (0x0, dev.control_port); 
-	outb (0x80 | 0x40 | bits, dev.data_port);	
-	wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
-					 dev.control_port,
-					 (reset_time*HZ)/100);
-
-	reported_irq = probe_irq_off (irq_mask);
-
-	if (reported_irq != dev.irq) {
-		if (reported_irq == 0) {
-			printk (KERN_ERR LOGNAME
-				"No unassigned interrupts detected "
-				"after h/w reset\n");
-		} else if (reported_irq < 0) {
-			printk (KERN_ERR LOGNAME
-				"Multiple unassigned interrupts detected "
-				"after h/w reset\n");
-		} else {
-			printk (KERN_ERR LOGNAME "autodetected IRQ %d not the "
-				"value provided (%d)\n", reported_irq,
-				dev.irq);
-		}
-		dev.irq = -1;
-		return 1;
-	} else {
-		printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n",
-			reported_irq);
-	}
-
-	if (request_irq (dev.irq, wavefrontintr,
-			 IRQF_DISABLED|IRQF_SHARED,
-			 "wavefront synth", &dev) < 0) {
-		printk (KERN_WARNING LOGNAME "IRQ %d not available!\n",
-			dev.irq);
-		return 1;
-	}
-
-	/* try reset of port */
-      
-	outb (0x0, dev.control_port); 
-  
-	/* At this point, the board is in reset, and the H/W initialization
-	   register is accessed at the same address as the data port.
-     
-	   Bit 7 - Enable IRQ Driver	
-	   0 - Tri-state the Wave-Board drivers for the PC Bus IRQs
-	   1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus.
-     
-	   Bit 6 - MIDI Interface Select
-
-	   0 - Use the MIDI Input from the 26-pin WaveBlaster
-	   compatible header as the serial MIDI source
-	   1 - Use the MIDI Input from the 9-pin D connector as the
-	   serial MIDI source.
-     
-	   Bits 5:3 - IRQ Selection
-	   0 0 0 - IRQ 2/9
-	   0 0 1 - IRQ 5
-	   0 1 0 - IRQ 12
-	   0 1 1 - IRQ 15
-	   1 0 0 - Reserved
-	   1 0 1 - Reserved
-	   1 1 0 - Reserved
-	   1 1 1 - Reserved
-     
-	   Bits 2:1 - Reserved
-	   Bit 0 - Disable Boot ROM
-	   0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM
-	   1 - memory accesses to 03FC30-03FFFFH are directed to external 
-	   storage.
-     
-	*/
-
-	/* configure hardware: IRQ, enable interrupts, 
-	   plus external 9-pin MIDI interface selected
-	*/
-
-	outb (0x80 | 0x40 | bits, dev.data_port);	
-  
-	/* CONTROL REGISTER
-
-	   0 Host Rx Interrupt Enable (1=Enabled)      0x1
-	   1 Unused                                    0x2
-	   2 Unused                                    0x4
-	   3 Unused                                    0x8
-	   4 Host Tx Interrupt Enable                 0x10
-	   5 Mute (0=Mute; 1=Play)                    0x20
-	   6 Master Interrupt Enable (1=Enabled)      0x40
-	   7 Master Reset (0=Reset; 1=Run)            0x80
-
-	   Take us out of reset, mute output, master + TX + RX interrupts on.
-	   
-	   We'll get an interrupt presumably to tell us that the TX
-	   register is clear.
-	*/
-
-	wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
-					 dev.control_port,
-					 (reset_time*HZ)/100);
-
-	/* Note: data port is now the data port, not the h/w initialization
-	   port.
-	 */
-
-	if (!dev.irq_ok) {
-		printk (KERN_WARNING LOGNAME
-			"intr not received after h/w un-reset.\n");
-		goto gone_bad;
-	} 
-
-	dev.interrupts_on = 1;
-	
-	/* Note: data port is now the data port, not the h/w initialization
-	   port.
-
-	   At this point, only "HW VERSION" or "DOWNLOAD OS" commands
-	   will work. So, issue one of them, and wait for TX
-	   interrupt. This can take a *long* time after a cold boot,
-	   while the ISC ROM does its RAM test. The SDK says up to 4
-	   seconds - with 12MB of RAM on a Tropez+, it takes a lot
-	   longer than that (~16secs). Note that the card understands
-	   the difference between a warm and a cold boot, so
-	   subsequent ISC2115 reboots (say, caused by module
-	   reloading) will get through this much faster.
-
-	   XXX Interesting question: why is no RX interrupt received first ?
-	*/
-
-	wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION, 
-					 dev.data_port, ramcheck_time*HZ);
-
-	if (!dev.irq_ok) {
-		printk (KERN_WARNING LOGNAME
-			"post-RAM-check interrupt not received.\n");
-		goto gone_bad;
-	} 
-
-	if (!wavefront_wait (STAT_CAN_READ)) {
-		printk (KERN_WARNING LOGNAME
-			"no response to HW version cmd.\n");
-		goto gone_bad;
-	}
-	
-	if ((hwv[0] = wavefront_read ()) == -1) {
-		printk (KERN_WARNING LOGNAME
-			"board not responding correctly.\n");
-		goto gone_bad;
-	}
-
-	if (hwv[0] == 0xFF) { /* NAK */
-
-		/* Board's RAM test failed. Try to read error code,
-		   and tell us about it either way.
-		*/
-		
-		if ((hwv[0] = wavefront_read ()) == -1) {
-			printk (KERN_WARNING LOGNAME "on-board RAM test failed "
-				"(bad error code).\n");
-		} else {
-			printk (KERN_WARNING LOGNAME "on-board RAM test failed "
-				"(error code: 0x%x).\n",
-				hwv[0]);
-		}
-		goto gone_bad;
-	}
-
-	/* We're OK, just get the next byte of the HW version response */
-
-	if ((hwv[1] = wavefront_read ()) == -1) {
-		printk (KERN_WARNING LOGNAME "incorrect h/w response.\n");
-		goto gone_bad;
-	}
-
-	printk (KERN_INFO LOGNAME "hardware version %d.%d\n",
-		hwv[0], hwv[1]);
-
-	return 0;
-
-
-     gone_bad:
-	if (dev.irq >= 0) {
-		free_irq (dev.irq, &dev);
-		dev.irq = -1;
-	}
-	return (1);
-}
-
-static int __init detect_wavefront (int irq, int io_base)
-{
-	unsigned char   rbuf[4], wbuf[4];
-
-	/* TB docs say the device takes up 8 ports, but we know that
-	   if there is an FX device present (i.e. a Tropez+) it really
-	   consumes 16.
-	*/
-
-	if (!request_region (io_base, 16, "wavfront")) {
-		printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x "
-			"already in use - ignored\n", dev.base,
-			dev.base+15);
-		return -1;
-	}
-  
-	dev.irq = irq;
-	dev.base = io_base;
-	dev.israw = 0;
-	dev.debug = debug_default;
-	dev.interrupts_on = 0;
-	dev.irq_cnt = 0;
-	dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */
-
-	if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) {
-
-		dev.fw_version[0] = rbuf[0];
-		dev.fw_version[1] = rbuf[1];
-		printk (KERN_INFO LOGNAME
-			"firmware %d.%d already loaded.\n",
-			rbuf[0], rbuf[1]);
-
-		/* check that a command actually works */
-      
-		if (wavefront_cmd (WFC_HARDWARE_VERSION,
-				   rbuf, wbuf) == 0) {
-			dev.hw_version[0] = rbuf[0];
-			dev.hw_version[1] = rbuf[1];
-		} else {
-			printk (KERN_WARNING LOGNAME "not raw, but no "
-				"hardware version!\n");
-			release_region (io_base, 16);
-			return 0;
-		}
-
-		if (!wf_raw) {
-			/* will re-acquire region in install_wavefront() */
-			release_region (io_base, 16);
-			return 1;
-		} else {
-			printk (KERN_INFO LOGNAME
-				"reloading firmware anyway.\n");
-			dev.israw = 1;
-		}
-
-	} else {
-
-		dev.israw = 1;
-		printk (KERN_INFO LOGNAME
-			"no response to firmware probe, assume raw.\n");
-
-	}
-
-	init_waitqueue_head (&dev.interrupt_sleeper);
-
-	if (wavefront_hw_reset ()) {
-		printk (KERN_WARNING LOGNAME "hardware reset failed\n");
-		release_region (io_base, 16);
-		return 0;
-	}
-
-	/* Check for FX device, present only on Tropez+ */
-
-	dev.has_fx = (detect_wffx () == 0);
-
-	/* will re-acquire region in install_wavefront() */
-	release_region (io_base, 16);
-	return 1;
-}
-
-#include "os.h"
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-
-
-static int
-wavefront_download_firmware (char *path)
-
-{
-	unsigned char section[WF_SECTION_MAX];
-	char section_length; /* yes, just a char; max value is WF_SECTION_MAX */
-	int section_cnt_downloaded = 0;
-	int fd;
-	int c;
-	int i;
-	mm_segment_t fs;
-
-	/* This tries to be a bit cleverer than the stuff Alan Cox did for
-	   the generic sound firmware, in that it actually knows
-	   something about the structure of the Motorola firmware. In
-	   particular, it uses a version that has been stripped of the
-	   20K of useless header information, and had section lengths
-	   added, making it possible to load the entire OS without any
-	   [kv]malloc() activity, since the longest entity we ever read is
-	   42 bytes (well, WF_SECTION_MAX) long.
-	*/
-
-	fs = get_fs();
-	set_fs (get_ds());
-
-	if ((fd = sys_open (path, 0, 0)) < 0) {
-		printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n",
-			path);
-		return 1;
-	}
-
-	while (1) {
-		int x;
-
-		if ((x = sys_read (fd, &section_length, sizeof (section_length))) !=
-		    sizeof (section_length)) {
-			printk (KERN_ERR LOGNAME "firmware read error.\n");
-			goto failure;
-		}
-
-		if (section_length == 0) {
-			break;
-		}
-
-		if (sys_read (fd, section, section_length) != section_length) {
-			printk (KERN_ERR LOGNAME "firmware section "
-				"read error.\n");
-			goto failure;
-		}
-
-		/* Send command */
-	
-		if (wavefront_write (WFC_DOWNLOAD_OS)) {
-			goto failure;
-		}
-	
-		for (i = 0; i < section_length; i++) {
-			if (wavefront_write (section[i])) {
-				goto failure;
-			}
-		}
-	
-		/* get ACK */
-	
-		if (wavefront_wait (STAT_CAN_READ)) {
-
-			if ((c = inb (dev.data_port)) != WF_ACK) {
-
-				printk (KERN_ERR LOGNAME "download "
-					"of section #%d not "
-					"acknowledged, ack = 0x%x\n",
-					section_cnt_downloaded + 1, c);
-				goto failure;
-		
-			}
-
-		} else {
-			printk (KERN_ERR LOGNAME "time out for firmware ACK.\n");
-			goto failure;
-		}
-
-	}
-
-	sys_close (fd);
-	set_fs (fs);
-	return 0;
-
- failure:
-	sys_close (fd);
-	set_fs (fs);
-	printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n");
-	return 1;
-}
-
-static int __init wavefront_config_midi (void)
-{
-	unsigned char rbuf[4], wbuf[4];
-    
-	if (detect_wf_mpu (dev.irq, dev.base) < 0) {
-		printk (KERN_WARNING LOGNAME
-			"could not find working MIDI device\n");
-		return -1;
-	} 
-
-	if ((dev.mididev = install_wf_mpu ()) < 0) {
-		printk (KERN_WARNING LOGNAME
-			"MIDI interfaces not configured\n");
-		return -1;
-	}
-
-	/* Route external MIDI to WaveFront synth (by default) */
-    
-	if (wavefront_cmd (WFC_MISYNTH_ON, rbuf, wbuf)) {
-		printk (KERN_WARNING LOGNAME
-			"cannot enable MIDI-IN to synth routing.\n");
-		/* XXX error ? */
-	}
-
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-	/* Get the regular MIDI patch loading function, so we can
-	   use it if we ever get handed a SYSEX patch. This is
-	   unlikely, because its so damn slow, but we may as well
-	   leave this functionality from maui.c behind, since it
-	   could be useful for sequencer applications that can
-	   only use MIDI to do patch loading.
-	*/
-
-	if (midi_devs[dev.mididev]->converter != NULL) {
-		midi_load_patch = midi_devs[dev.mididev]->converter->load_patch;
-		midi_devs[dev.mididev]->converter->load_patch =
-		    &wavefront_oss_load_patch;
-	}
-
-#endif /* OSS_SUPPORT_SEQ */
-	
-	/* Turn on Virtual MIDI, but first *always* turn it off,
-	   since otherwise consectutive reloads of the driver will
-	   never cause the hardware to generate the initial "internal" or 
-	   "external" source bytes in the MIDI data stream. This
-	   is pretty important, since the internal hardware generally will
-	   be used to generate none or very little MIDI output, and
-	   thus the only source of MIDI data is actually external. Without
-	   the switch bytes, the driver will think it all comes from
-	   the internal interface. Duh.
-	*/
-
-	if (wavefront_cmd (WFC_VMIDI_OFF, rbuf, wbuf)) { 
-		printk (KERN_WARNING LOGNAME
-			"virtual MIDI mode not disabled\n");
-		return 0; /* We're OK, but missing the external MIDI dev */
-	}
-
-	if ((dev.ext_mididev = virtual_midi_enable ()) < 0) {
-		printk (KERN_WARNING LOGNAME "no virtual MIDI access.\n");
-	} else {
-		if (wavefront_cmd (WFC_VMIDI_ON, rbuf, wbuf)) {
-			printk (KERN_WARNING LOGNAME
-				"cannot enable virtual MIDI mode.\n");
-			virtual_midi_disable ();
-		} 
-	}
-    
-	return 0;
-}
-
-static int __init wavefront_do_reset (int atboot)
-{
-	char voices[1];
-
-	if (!atboot && wavefront_hw_reset ()) {
-		printk (KERN_WARNING LOGNAME "hw reset failed.\n");
-		goto gone_bad;
-	}
-
-	if (dev.israw) {
-		if (wavefront_download_firmware (ospath)) {
-			goto gone_bad;
-		}
-
-		dev.israw = 0;
-
-		/* Wait for the OS to get running. The protocol for
-		   this is non-obvious, and was determined by
-		   using port-IO tracing in DOSemu and some
-		   experimentation here.
-		   
-		   Rather than using timed waits, use interrupts creatively.
-		*/
-
-		wavefront_should_cause_interrupt (WFC_NOOP,
-						  dev.data_port,
-						  (osrun_time*HZ));
-
-		if (!dev.irq_ok) {
-			printk (KERN_WARNING LOGNAME
-				"no post-OS interrupt.\n");
-			goto gone_bad;
-		}
-		
-		/* Now, do it again ! */
-		
-		wavefront_should_cause_interrupt (WFC_NOOP,
-						  dev.data_port, (10*HZ));
-		
-		if (!dev.irq_ok) {
-			printk (KERN_WARNING LOGNAME
-				"no post-OS interrupt(2).\n");
-			goto gone_bad;
-		}
-
-		/* OK, no (RX/TX) interrupts any more, but leave mute
-		   in effect. 
-		*/
-		
-		outb (0x80|0x40, dev.control_port); 
-
-		/* No need for the IRQ anymore */
-		
-		free_irq (dev.irq, &dev);
-
-	}
-
-	if (dev.has_fx && fx_raw) {
-		wffx_init ();
-	}
-
-	/* SETUPSND.EXE asks for sample memory config here, but since i
-	   have no idea how to interpret the result, we'll forget
-	   about it.
-	*/
-	
-	if ((dev.freemem = wavefront_freemem ()) < 0) {
-		goto gone_bad;
-	}
-		
-	printk (KERN_INFO LOGNAME "available DRAM %dk\n", dev.freemem / 1024);
-
-	if (wavefront_write (0xf0) ||
-	    wavefront_write (1) ||
-	    (wavefront_read () < 0)) {
-		dev.debug = 0;
-		printk (KERN_WARNING LOGNAME "MPU emulation mode not set.\n");
-		goto gone_bad;
-	}
-
-	voices[0] = 32;
-
-	if (wavefront_cmd (WFC_SET_NVOICES, NULL, voices)) {
-		printk (KERN_WARNING LOGNAME
-			"cannot set number of voices to 32.\n");
-		goto gone_bad;
-	}
-
-
-	return 0;
-
- gone_bad:
-	/* reset that sucker so that it doesn't bother us. */
-
-	outb (0x0, dev.control_port);
-	dev.interrupts_on = 0;
-	if (dev.irq >= 0) {
-		free_irq (dev.irq, &dev);
-	}
-	return 1;
-}
-
-static int __init wavefront_init (int atboot)
-{
-	int samples_are_from_rom;
-
-	if (dev.israw) {
-		samples_are_from_rom = 1;
-	} else {
-		/* XXX is this always true ? */
-		samples_are_from_rom = 0;
-	}
-
-	if (dev.israw || fx_raw) {
-		if (wavefront_do_reset (atboot)) {
-			return -1;
-		}
-	}
-
-	wavefront_get_sample_status (samples_are_from_rom);
-	wavefront_get_program_status ();
-	wavefront_get_patch_status ();
-
-	/* Start normal operation: unreset, master interrupt enabled, no mute
-	*/
-
-	outb (0x80|0x40|0x20, dev.control_port); 
-
-	return (0);
-}
-
-static int __init install_wavefront (void)
-{
-	if (!request_region (dev.base+2, 6, "wavefront synth"))
-		return -1;
-
-	if (dev.has_fx) {
-		if (!request_region (dev.base+8, 8, "wavefront fx")) {
-			release_region (dev.base+2, 6);
-			return -1;
-		}
-	}
-
-	if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) {
-		printk (KERN_ERR LOGNAME "cannot register raw synth\n");
-		goto err_out;
-	}
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-	if ((dev.oss_dev = sound_alloc_synthdev()) == -1) {
-		printk (KERN_ERR LOGNAME "Too many sequencers\n");
-		/* FIXME: leak: should unregister sound synth */
-		goto err_out;
-	} else {
-		synth_devs[dev.oss_dev] = &wavefront_operations;
-	}
-#endif /* OSS_SUPPORT_SEQ */
-
-	if (wavefront_init (1) < 0) {
-		printk (KERN_WARNING LOGNAME "initialization failed.\n");
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-		sound_unload_synthdev (dev.oss_dev);
-#endif /* OSS_SUPPORT_SEQ */ 
-
-		goto err_out;
-	}
-    
-	if (wavefront_config_midi ()) {
-		printk (KERN_WARNING LOGNAME "could not initialize MIDI.\n");
-	}
-
-	return dev.oss_dev;
-
-err_out:
-	release_region (dev.base+2, 6);
-	if (dev.has_fx)
-		release_region (dev.base+8, 8);
-	return -1;
-}
-
-static void __exit uninstall_wavefront (void)
-{
-	/* the first two i/o addresses are freed by the wf_mpu code */
-	release_region (dev.base+2, 6);
-
-	if (dev.has_fx) {
-		release_region (dev.base+8, 8);
-	}
-
-	unregister_sound_synth (dev.synth_dev);
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-	sound_unload_synthdev (dev.oss_dev);
-#endif /* OSS_SUPPORT_SEQ */ 
-	uninstall_wf_mpu ();
-}
-
-/***********************************************************************/
-/*   WaveFront FX control                                              */
-/***********************************************************************/
-
-#include "yss225.h"
-
-/* Control bits for the Load Control Register
- */
-
-#define FX_LSB_TRANSFER 0x01    /* transfer after DSP LSB byte written */
-#define FX_MSB_TRANSFER 0x02    /* transfer after DSP MSB byte written */
-#define FX_AUTO_INCR    0x04    /* auto-increment DSP address after transfer */
-
-static int
-wffx_idle (void) 
-    
-{
-	int i;
-	unsigned int x = 0x80;
-    
-	for (i = 0; i < 1000; i++) {
-		x = inb (dev.fx_status);
-		if ((x & 0x80) == 0) {
-			break;
-		}
-	}
-    
-	if (x & 0x80) {
-		printk (KERN_ERR LOGNAME "FX device never idle.\n");
-		return 0;
-	}
-    
-	return (1);
-}
-
-int __init detect_wffx (void)
-{
-	/* This is a crude check, but its the best one I have for now.
-	   Certainly on the Maui and the Tropez, wffx_idle() will
-	   report "never idle", which suggests that this test should
-	   work OK.
-	*/
-
-	if (inb (dev.fx_status) & 0x80) {
-		printk (KERN_INFO LOGNAME "Hmm, probably a Maui or Tropez.\n");
-		return -1;
-	}
-
-	return 0;
-}	
-
-static void
-wffx_mute (int onoff)
-    
-{
-	if (!wffx_idle()) {
-		return;
-	}
-    
-	outb (onoff ? 0x02 : 0x00, dev.fx_op);
-}
-
-static int
-wffx_memset (int page,
-	     int addr, int cnt, unsigned short *data)
-{
-	if (page < 0 || page > 7) {
-		printk (KERN_ERR LOGNAME "FX memset: "
-			"page must be >= 0 and <= 7\n");
-		return -(EINVAL);
-	}
-
-	if (addr < 0 || addr > 0x7f) {
-		printk (KERN_ERR LOGNAME "FX memset: "
-			"addr must be >= 0 and <= 7f\n");
-		return -(EINVAL);
-	}
-
-	if (cnt == 1) {
-
-		outb (FX_LSB_TRANSFER, dev.fx_lcr);
-		outb (page, dev.fx_dsp_page);
-		outb (addr, dev.fx_dsp_addr);
-		outb ((data[0] >> 8), dev.fx_dsp_msb);
-		outb ((data[0] & 0xff), dev.fx_dsp_lsb);
-
-		printk (KERN_INFO LOGNAME "FX: addr %d:%x set to 0x%x\n",
-			page, addr, data[0]);
-	
-	} else {
-		int i;
-
-		outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-		outb (page, dev.fx_dsp_page);
-		outb (addr, dev.fx_dsp_addr);
-
-		for (i = 0; i < cnt; i++) {
-			outb ((data[i] >> 8), dev.fx_dsp_msb);
-			outb ((data[i] & 0xff), dev.fx_dsp_lsb);
-			if (!wffx_idle ()) {
-				break;
-			}
-		}
-
-		if (i != cnt) {
-			printk (KERN_WARNING LOGNAME
-				"FX memset "
-				"(0x%x, 0x%x, %p, %d) incomplete\n",
-				page, addr, data, cnt);
-			return -(EIO);
-		}
-	}
-
-	return 0;
-}
-
-static int
-wffx_ioctl (wavefront_fx_info *r)
-
-{
-	unsigned short page_data[256];
-	unsigned short *pd;
-
-	switch (r->request) {
-	case WFFX_MUTE:
-		wffx_mute (r->data[0]);
-		return 0;
-
-	case WFFX_MEMSET:
-
-		if (r->data[2] <= 0) {
-			printk (KERN_ERR LOGNAME "cannot write "
-				"<= 0 bytes to FX\n");
-			return -(EINVAL);
-		} else if (r->data[2] == 1) {
-			pd = (unsigned short *) &r->data[3];
-		} else {
-			if (r->data[2] > sizeof (page_data)) {
-				printk (KERN_ERR LOGNAME "cannot write "
-					"> 255 bytes to FX\n");
-				return -(EINVAL);
-			}
-			if (copy_from_user(page_data,
-					   (unsigned char __user *)r->data[3],
-					   r->data[2]))
-				return -EFAULT;
-			pd = page_data;
-		}
-
-		return wffx_memset (r->data[0], /* page */
-				    r->data[1], /* addr */
-				    r->data[2], /* cnt */
-				    pd);
-
-	default:
-		printk (KERN_WARNING LOGNAME
-			"FX: ioctl %d not yet supported\n",
-			r->request);
-		return -(EINVAL);
-	}
-}
-
-/* YSS225 initialization.
-
-   This code was developed using DOSEMU. The Turtle Beach SETUPSND
-   utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
-   of the port I/O done, using the Yamaha faxback document as a guide
-   to add more logic to the code. Its really pretty weird.
-
-   There was an alternative approach of just dumping the whole I/O
-   sequence as a series of port/value pairs and a simple loop
-   that output it. However, I hope that eventually I'll get more
-   control over what this code does, and so I tried to stick with
-   a somewhat "algorithmic" approach.
-*/
-
-static int __init wffx_init (void)
-{
-	int i;
-	int j;
-
-	/* Set all bits for all channels on the MOD unit to zero */
-	/* XXX But why do this twice ? */
-
-	for (j = 0; j < 2; j++) {
-		for (i = 0x10; i <= 0xff; i++) {
-	    
-			if (!wffx_idle ()) {
-				return (-1);
-			}
-	    
-			outb (i, dev.fx_mod_addr);
-			outb (0x0, dev.fx_mod_data);
-		}
-	}
-
-	if (!wffx_idle()) return (-1);
-	outb (0x02, dev.fx_op);                        /* mute on */
-
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x44, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x42, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x43, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x7c, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x7e, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x46, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x49, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x47, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x4a, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-
-	/* either because of stupidity by TB's programmers, or because it
-	   actually does something, rezero the MOD page.
-	*/
-	for (i = 0x10; i <= 0xff; i++) {
-	
-		if (!wffx_idle ()) {
-			return (-1);
-		}
-	
-		outb (i, dev.fx_mod_addr);
-		outb (0x0, dev.fx_mod_data);
-	}
-	/* load page zero */
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x00, dev.fx_dsp_page);
-	outb (0x00, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_zero); i += 2) {
-		outb (page_zero[i], dev.fx_dsp_msb);
-		outb (page_zero[i+1], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-
-	/* Now load page one */
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x01, dev.fx_dsp_page);
-	outb (0x00, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_one); i += 2) {
-		outb (page_one[i], dev.fx_dsp_msb);
-		outb (page_one[i+1], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x02, dev.fx_dsp_page);
-	outb (0x00, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_two); i++) {
-		outb (page_two[i], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x03, dev.fx_dsp_page);
-	outb (0x00, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_three); i++) {
-		outb (page_three[i], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x04, dev.fx_dsp_page);
-	outb (0x00, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_four); i++) {
-		outb (page_four[i], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-
-	/* Load memory area (page six) */
-    
-	outb (FX_LSB_TRANSFER, dev.fx_lcr); 
-	outb (0x06, dev.fx_dsp_page); 
-
-	for (i = 0; i < sizeof (page_six); i += 3) {
-		outb (page_six[i], dev.fx_dsp_addr);
-		outb (page_six[i+1], dev.fx_dsp_msb);
-		outb (page_six[i+2], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x00, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_seven); i += 2) {
-		outb (page_seven[i], dev.fx_dsp_msb);
-		outb (page_seven[i+1], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-
-	/* Now setup the MOD area. We do this algorithmically in order to
-	   save a little data space. It could be done in the same fashion
-	   as the "pages".
-	*/
-
-	for (i = 0x00; i <= 0x0f; i++) {
-		outb (0x01, dev.fx_mod_addr);
-		outb (i, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-		outb (0x02, dev.fx_mod_addr);
-		outb (0x00, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0xb0; i <= 0xbf; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x20, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0xf0; i <= 0xff; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x20, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0x10; i <= 0x1d; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0xff, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (0x1e, dev.fx_mod_addr);
-	outb (0x40, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	for (i = 0x1f; i <= 0x2d; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0xff, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (0x2e, dev.fx_mod_addr);
-	outb (0x00, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	for (i = 0x2f; i <= 0x3e; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x00, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (0x3f, dev.fx_mod_addr);
-	outb (0x20, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	for (i = 0x40; i <= 0x4d; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x00, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (0x4e, dev.fx_mod_addr);
-	outb (0x0e, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-	outb (0x4f, dev.fx_mod_addr);
-	outb (0x0e, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-
-	for (i = 0x50; i <= 0x6b; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x00, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (0x6c, dev.fx_mod_addr);
-	outb (0x40, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	outb (0x6d, dev.fx_mod_addr);
-	outb (0x00, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	outb (0x6e, dev.fx_mod_addr);
-	outb (0x40, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	outb (0x6f, dev.fx_mod_addr);
-	outb (0x40, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	for (i = 0x70; i <= 0x7f; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0xc0, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	for (i = 0x80; i <= 0xaf; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x00, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0xc0; i <= 0xdd; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x00, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (0xde, dev.fx_mod_addr);
-	outb (0x10, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-	outb (0xdf, dev.fx_mod_addr);
-	outb (0x10, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-
-	for (i = 0xe0; i <= 0xef; i++) {
-		outb (i, dev.fx_mod_addr);
-		outb (0x00, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0x00; i <= 0x0f; i++) {
-		outb (0x01, dev.fx_mod_addr);
-		outb (i, dev.fx_mod_data);
-		outb (0x02, dev.fx_mod_addr);
-		outb (0x01, dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (0x02, dev.fx_op); /* mute on */
-
-	/* Now set the coefficients and so forth for the programs above */
-
-	for (i = 0; i < sizeof (coefficients); i += 4) {
-		outb (coefficients[i], dev.fx_dsp_page);
-		outb (coefficients[i+1], dev.fx_dsp_addr);
-		outb (coefficients[i+2], dev.fx_dsp_msb);
-		outb (coefficients[i+3], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-
-	/* Some settings (?) that are too small to bundle into loops */
-
-	if (!wffx_idle()) return (-1);
-	outb (0x1e, dev.fx_mod_addr);
-	outb (0x14, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-	outb (0xde, dev.fx_mod_addr);
-	outb (0x20, dev.fx_mod_data);
-	if (!wffx_idle()) return (-1);
-	outb (0xdf, dev.fx_mod_addr);
-	outb (0x20, dev.fx_mod_data);
-    
-	/* some more coefficients */
-
-	if (!wffx_idle()) return (-1);
-	outb (0x06, dev.fx_dsp_page);
-	outb (0x78, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x40, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x03, dev.fx_dsp_addr);
-	outb (0x0f, dev.fx_dsp_msb);
-	outb (0xff, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x0b, dev.fx_dsp_addr);
-	outb (0x0f, dev.fx_dsp_msb);
-	outb (0xff, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x02, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x0a, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x46, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-	if (!wffx_idle()) return (-1);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x49, dev.fx_dsp_addr);
-	outb (0x00, dev.fx_dsp_msb);
-	outb (0x00, dev.fx_dsp_lsb);
-    
-	/* Now, for some strange reason, lets reload every page
-	   and all the coefficients over again. I have *NO* idea
-	   why this is done. I do know that no sound is produced
-	   is this phase is omitted.
-	*/
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x00, dev.fx_dsp_page);  
-	outb (0x10, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_zero_v2); i += 2) {
-		outb (page_zero_v2[i], dev.fx_dsp_msb);
-		outb (page_zero_v2[i+1], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x01, dev.fx_dsp_page);
-	outb (0x10, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_one_v2); i += 2) {
-		outb (page_one_v2[i], dev.fx_dsp_msb);
-		outb (page_one_v2[i+1], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	if (!wffx_idle()) return (-1);
-	if (!wffx_idle()) return (-1);
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x02, dev.fx_dsp_page);
-	outb (0x10, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_two_v2); i++) {
-		outb (page_two_v2[i], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x03, dev.fx_dsp_page);
-	outb (0x10, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_three_v2); i++) {
-		outb (page_three_v2[i], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x04, dev.fx_dsp_page);
-	outb (0x10, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_four_v2); i++) {
-		outb (page_four_v2[i], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-    
-	outb (FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x06, dev.fx_dsp_page);
-
-	/* Page six v.2 is algorithmic */
-    
-	for (i = 0x10; i <= 0x3e; i += 2) {
-		outb (i, dev.fx_dsp_addr);
-		outb (0x00, dev.fx_dsp_msb);
-		outb (0x00, dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-
-	outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
-	outb (0x07, dev.fx_dsp_page);
-	outb (0x10, dev.fx_dsp_addr);
-
-	for (i = 0; i < sizeof (page_seven_v2); i += 2) {
-		outb (page_seven_v2[i], dev.fx_dsp_msb);
-		outb (page_seven_v2[i+1], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0x00; i < sizeof(mod_v2); i += 2) {
-		outb (mod_v2[i], dev.fx_mod_addr);
-		outb (mod_v2[i+1], dev.fx_mod_data);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0; i < sizeof (coefficients2); i += 4) {
-		outb (coefficients2[i], dev.fx_dsp_page);
-		outb (coefficients2[i+1], dev.fx_dsp_addr);
-		outb (coefficients2[i+2], dev.fx_dsp_msb);
-		outb (coefficients2[i+3], dev.fx_dsp_lsb);
-		if (!wffx_idle()) return (-1);
-	}
-
-	for (i = 0; i < sizeof (coefficients3); i += 2) {
-		int x;
-
-		outb (0x07, dev.fx_dsp_page);
-		x = (i % 4) ? 0x4e : 0x4c;
-		outb (x, dev.fx_dsp_addr);
-		outb (coefficients3[i], dev.fx_dsp_msb);
-		outb (coefficients3[i+1], dev.fx_dsp_lsb);
-	}
-
-	outb (0x00, dev.fx_op); /* mute off */
-	if (!wffx_idle()) return (-1);
-
-	return (0);
-}
-
-static int io = -1;
-static int irq = -1;
-
-MODULE_AUTHOR      ("Paul Barton-Davis <pbd@op.net>");
-MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver");
-MODULE_LICENSE("GPL");
-module_param       (io, int, 0);
-module_param       (irq, int, 0);
-
-static int __init init_wavfront (void)
-{
-	printk ("Turtle Beach WaveFront Driver\n"
-		"Copyright (C) by Hannu Solvainen, "
-		"Paul Barton-Davis 1993-1998.\n");
-
-	/* XXX t'would be lovely to ask the CS4232 for these values, eh ? */
-
-	if (io == -1 || irq == -1) {
-		printk (KERN_INFO LOGNAME "irq and io options must be set.\n");
-		return -EINVAL;
-	}
-
-	if (wavefront_interrupt_bits (irq) < 0) {
-		printk (KERN_INFO LOGNAME
-			"IRQ must be 9, 5, 12 or 15 (not %d)\n", irq);
-		return -ENODEV;
-	}
-
-	if (detect_wavefront (irq, io) < 0) {
-		return -ENODEV;
-	} 
-
-	if (install_wavefront () < 0) {
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static void __exit cleanup_wavfront (void)
-{
-	uninstall_wavefront ();
-}
-
-module_init(init_wavfront);
-module_exit(cleanup_wavfront);
diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c
deleted file mode 100644
index 75c0c14..0000000
--- a/sound/oss/wf_midi.c
+++ /dev/null
@@ -1,880 +0,0 @@
-/*
- * sound/oss/wf_midi.c
- *
- * The low level driver for the WaveFront ICS2115 MIDI interface(s)
- * Note that there is also an MPU-401 emulation (actually, a UART-401
- * emulation) on the CS4232 on the Tropez Plus. This code has nothing
- * to do with that interface at all.
- *
- * The interface is essentially just a UART-401, but is has the
- * interesting property of supporting what Turtle Beach called
- * "Virtual MIDI" mode. In this mode, there are effectively *two*
- * MIDI buses accessible via the interface, one that is routed
- * solely to/from the external WaveFront synthesizer and the other
- * corresponding to the pin/socket connector used to link external
- * MIDI devices to the board.
- *
- * This driver fully supports this mode, allowing two distinct
- * midi devices (/dev/midiNN and /dev/midiNN+1) to be used
- * completely independently, giving 32 channels of MIDI routing,
- * 16 to the WaveFront synth and 16 to the external MIDI bus.
- *
- * Switching between the two is accomplished externally by the driver
- * using the two otherwise unused MIDI bytes. See the code for more details.
- *
- * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see wavefront.c)
- *
- * The main reason to turn off Virtual MIDI mode is when you want to
- * tightly couple the WaveFront synth with an external MIDI
- * device. You won't be able to distinguish the source of any MIDI
- * data except via SysEx ID, but thats probably OK, since for the most
- * part, the WaveFront won't be sending any MIDI data at all.
- *  
- * The main reason to turn on Virtual MIDI Mode is to provide two
- * completely independent 16-channel MIDI buses, one to the
- * WaveFront and one to any external MIDI devices. Given the 32
- * voice nature of the WaveFront, its pretty easy to find a use
- * for all 16 channels driving just that synth.
- *
- */
-
-/*
- * Copyright (C) by Paul Barton-Davis 1998
- * Some portions of this file are derived from work that is:
- *
- *    CopyriGht (C) by Hannu Savolainen 1993-1996
- *
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include <linux/wavefront.h>
-
-#ifdef MODULE
-
-struct wf_mpu_config {
-	int             base;
-#define	DATAPORT(d)   (d)->base
-#define	COMDPORT(d)   (d)->base+1
-#define	STATPORT(d)   (d)->base+1
-
-	int             irq;
-	int             opened;
-	int             devno;
-	int             synthno;
-	int             mode;
-#define MODE_MIDI	1
-#define MODE_SYNTH	2
-
-	void            (*inputintr) (int dev, unsigned char data);
-	char isvirtual;                /* do virtual I/O stuff */
-};
-
-static struct wf_mpu_config  devs[2];
-static struct wf_mpu_config *phys_dev = &devs[0];
-static struct wf_mpu_config *virt_dev = &devs[1];
-
-static void start_uart_mode (void);
-static DEFINE_SPINLOCK(lock);
-
-#define	OUTPUT_READY	0x40
-#define	INPUT_AVAIL	0x80
-#define	MPU_ACK		0xFE
-#define	UART_MODE_ON	0x3F
-
-static inline int wf_mpu_status (void)
-{
-	return inb (STATPORT (phys_dev));
-}
-
-static inline int input_avail (void)
-{
-	return !(wf_mpu_status() & INPUT_AVAIL);
-}
-
-static inline int output_ready (void)
-{
-	return !(wf_mpu_status() & OUTPUT_READY);
-}
-
-static inline int  read_data (void)
-{
-	return inb (DATAPORT (phys_dev));
-}
-
-static inline void write_data (unsigned char byte)
-{
-	outb (byte, DATAPORT (phys_dev));
-}
-
-/*
- * States for the input scanner (should be in dev_table.h)
- */
-
-#define MST_SYSMSG		100	/* System message (sysx etc). */
-#define MST_MTC			102	/* Midi Time Code (MTC) qframe msg */
-#define MST_SONGSEL		103	/* Song select */
-#define MST_SONGPOS		104	/* Song position pointer */
-#define MST_TIMED		105	/* Leading timing byte rcvd */
-
-/* buffer space check for input scanner */
-
-#define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \
-{printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \
-	mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;}
-
-static unsigned char len_tab[] =	/* # of data bytes following a status
-					 */
-{
-	2,				/* 8x */
-	2,				/* 9x */
-	2,				/* Ax */
-	2,				/* Bx */
-	1,				/* Cx */
-	1,				/* Dx */
-	2,				/* Ex */
-	0				/* Fx */
-};
-
-static int
-wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic)
-
-{
-	struct midi_input_info *mi = &midi_devs[devno]->in_info;
-
-	switch (mi->m_state) {
-	case MST_INIT:
-		switch (midic) {
-		case 0xf8:
-			/* Timer overflow */
-			break;
-		
-		case 0xfc:
-			break;
-		
-		case 0xfd:
-			/* XXX do something useful with this. If there is
-			   an external MIDI timer (e.g. a hardware sequencer,
-			   a useful timer can be derived ...
-		   
-			   For now, no timer support.
-			*/
-			break;
-		
-		case 0xfe:
-			return MPU_ACK;
-			break;
-		
-		case 0xf0:
-		case 0xf1:
-		case 0xf2:
-		case 0xf3:
-		case 0xf4:
-		case 0xf5:
-		case 0xf6:
-		case 0xf7:
-			break;
-		
-		case 0xf9:
-			break;
-		
-		case 0xff:
-			mi->m_state = MST_SYSMSG;
-			break;
-		
-		default:
-			if (midic <= 0xef) {
-				mi->m_state = MST_TIMED;
-			}
-			else
-				printk (KERN_ERR "<MPU: Unknown event %02x> ",
-					midic);
-		}
-		break;
-	  
-	case MST_TIMED:
-	{
-		int             msg = ((int) (midic & 0xf0) >> 4);
-	  
-		mi->m_state = MST_DATA;
-	  
-		if (msg < 8) {	/* Data byte */
-	      
-			msg = ((int) (mi->m_prev_status & 0xf0) >> 4);
-			msg -= 8;
-			mi->m_left = len_tab[msg] - 1;
-	      
-			mi->m_ptr = 2;
-			mi->m_buf[0] = mi->m_prev_status;
-			mi->m_buf[1] = midic;
-
-			if (mi->m_left <= 0) {
-				mi->m_state = MST_INIT;
-				do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
-				mi->m_ptr = 0;
-			}
-		} else if (msg == 0xf) {	/* MPU MARK */
-	      
-			mi->m_state = MST_INIT;
-
-			switch (midic) {
-			case 0xf8:
-				break;
-		    
-			case 0xf9:
-				break;
-		    
-			case 0xfc:
-				break;
-		    
-			default:
-				break;
-			}
-		} else {
-			mi->m_prev_status = midic;
-			msg -= 8;
-			mi->m_left = len_tab[msg];
-	      
-			mi->m_ptr = 1;
-			mi->m_buf[0] = midic;
-	      
-			if (mi->m_left <= 0) {
-				mi->m_state = MST_INIT;
-				do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
-				mi->m_ptr = 0;
-			}
-		}
-	}
-	break;
-
-	case MST_SYSMSG:
-		switch (midic) {
-		case 0xf0:
-			mi->m_state = MST_SYSEX;
-			break;
-	    
-		case 0xf1:
-			mi->m_state = MST_MTC;
-			break;
-
-		case 0xf2:
-			mi->m_state = MST_SONGPOS;
-			mi->m_ptr = 0;
-			break;
-	    
-		case 0xf3:
-			mi->m_state = MST_SONGSEL;
-			break;
-	    
-		case 0xf6:
-			mi->m_state = MST_INIT;
-	    
-			/*
-			 *    Real time messages
-			 */
-		case 0xf8:
-			/* midi clock */
-			mi->m_state = MST_INIT;
-			/* XXX need ext MIDI timer support */
-			break;
-	    
-		case 0xfA:
-			mi->m_state = MST_INIT;
-			/* XXX need ext MIDI timer support */
-			break;
-	    
-		case 0xFB:
-			mi->m_state = MST_INIT;
-			/* XXX need ext MIDI timer support */
-			break;
-	    
-		case 0xFC:
-			mi->m_state = MST_INIT;
-			/* XXX need ext MIDI timer support */
-			break;
-	    
-		case 0xFE:
-			/* active sensing */
-			mi->m_state = MST_INIT;
-			break;
-	    
-		case 0xff:
-			mi->m_state = MST_INIT;
-			break;
-
-		default:
-			printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic);
-			mi->m_state = MST_INIT;
-		}
-		break;
-
-	case MST_MTC:
-		mi->m_state = MST_INIT;
-		break;
-
-	case MST_SYSEX:
-		if (midic == 0xf7) {
-			mi->m_state = MST_INIT;
-		} else {
-			/* XXX fix me */
-		}
-		break;
-
-	case MST_SONGPOS:
-		BUFTEST (mi);
-		mi->m_buf[mi->m_ptr++] = midic;
-		if (mi->m_ptr == 2) {
-			mi->m_state = MST_INIT;
-			mi->m_ptr = 0;
-			/* XXX need ext MIDI timer support */
-		}
-		break;
-
-	case MST_DATA:
-		BUFTEST (mi);
-		mi->m_buf[mi->m_ptr++] = midic;
-		if ((--mi->m_left) <= 0) {
-			mi->m_state = MST_INIT;
-			do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
-			mi->m_ptr = 0;
-		}
-		break;
-
-	default:
-		printk (KERN_ERR "Bad state %d ", mi->m_state);
-		mi->m_state = MST_INIT;
-	}
-
-	return 1;
-}
-
-static irqreturn_t
-wf_mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
-
-{
-	struct wf_mpu_config *physical_dev = dev_id;
-	static struct wf_mpu_config *input_dev;
-	struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
-	int n;
-
-	if (!input_avail()) { /* not for us */
-		return IRQ_NONE;
-	}
-
-	if (mi->m_busy)
-		return IRQ_HANDLED;
-	spin_lock(&lock);
-	mi->m_busy = 1;
-
-	if (!input_dev) {
-		input_dev = physical_dev;
-	}
-
-	n = 50; /* XXX why ? */
-
-	do {
-		unsigned char c = read_data ();
-      
-		if (phys_dev->isvirtual) {
-
-			if (c == WF_EXTERNAL_SWITCH) {
-				input_dev = virt_dev;
-				continue;
-			} else if (c == WF_INTERNAL_SWITCH) { 
-				input_dev = phys_dev;
-				continue;
-			} /* else just leave it as it is */
-
-		} else {
-			input_dev = phys_dev;
-		}
-
-		if (input_dev->mode == MODE_SYNTH) {
-	  
-			wf_mpu_input_scanner (input_dev->devno,
-					      input_dev->synthno, c);
-	  
-		} else if (input_dev->opened & OPEN_READ) {
-	  
-			if (input_dev->inputintr) {
-				input_dev->inputintr (input_dev->devno, c);
-			} 
-		}
-
-	} while (input_avail() && n-- > 0);
-
-	mi->m_busy = 0;
-	spin_unlock(&lock);
-	return IRQ_HANDLED;
-}
-
-static int
-wf_mpu_open (int dev, int mode,
-	     void            (*input) (int dev, unsigned char data),
-	     void            (*output) (int dev)
-	)
-{
-	struct wf_mpu_config *devc;
-
-	if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
-		return -(ENXIO);
-
-	if (phys_dev->devno == dev) {
-		devc = phys_dev;
-	} else if (phys_dev->isvirtual && virt_dev->devno == dev) {
-		devc = virt_dev;
-	} else {
-		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
-		return -(EINVAL);
-	}
-
-	if (devc->opened) {
-		return -(EBUSY);
-	}
-
-	devc->mode = MODE_MIDI;
-	devc->opened = mode;
-	devc->synthno = 0;
-
-	devc->inputintr = input;
-	return 0;
-}
- 
-static void
-wf_mpu_close (int dev)
-{
-	struct wf_mpu_config *devc;
-
-	if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
-		return;
-
-	if (phys_dev->devno == dev) {
-		devc = phys_dev;
-	} else if (phys_dev->isvirtual && virt_dev->devno == dev) {
-		devc = virt_dev;
-	} else {
-		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
-		return;
-	}
-
-	devc->mode = 0;
-	devc->inputintr = NULL;
-	devc->opened = 0;
-}
-
-static int
-wf_mpu_out (int dev, unsigned char midi_byte)
-{
-	int             timeout;
-	unsigned long   flags;
-	static int lastoutdev = -1;
-	unsigned char switchch;
-
-	if (phys_dev->isvirtual && lastoutdev != dev) {
-      
-		if (dev == phys_dev->devno) { 
-			switchch = WF_INTERNAL_SWITCH;
-		} else if (dev == virt_dev->devno) { 
-			switchch = WF_EXTERNAL_SWITCH;
-		} else {
-			printk (KERN_ERR "WF-MPU: bad device number %d", dev);
-			return (0);
-		}
-
-		/* XXX fix me */
-      
-		for (timeout = 30000; timeout > 0 && !output_ready ();
-		     timeout--);
-      
-		spin_lock_irqsave(&lock,flags);
-      
-		if (!output_ready ()) {
-			printk (KERN_WARNING "WF-MPU: Send switch "
-				"byte timeout\n");
-			spin_unlock_irqrestore(&lock,flags);
-			return 0;
-		}
-      
-		write_data (switchch);
-		spin_unlock_irqrestore(&lock,flags);
-	} 
-
-	lastoutdev = dev;
-
-	/*
-	 * Sometimes it takes about 30000 loops before the output becomes ready
-	 * (After reset). Normally it takes just about 10 loops.
-	 */
-
-	/* XXX fix me */
-
-	for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
-
-	spin_lock_irqsave(&lock,flags);
-	if (!output_ready ()) {
-		spin_unlock_irqrestore(&lock,flags);
-		printk (KERN_WARNING "WF-MPU: Send data timeout\n");
-		return 0;
-	}
-
-	write_data (midi_byte);
-	spin_unlock_irqrestore(&lock,flags);
-
-	return 1;
-}
-
-static inline int wf_mpu_start_read (int dev) {
-	return 0;
-}
-
-static inline int wf_mpu_end_read (int dev) {
-	return 0;
-}
-
-static int wf_mpu_ioctl (int dev, unsigned cmd, void __user *arg)
-{
-	printk (KERN_WARNING
-		"WF-MPU: Intelligent mode not supported by hardware.\n");
-	return -(EINVAL);
-}
-
-static int wf_mpu_buffer_status (int dev)
-{
-	return 0;
-}
-
-static struct synth_operations wf_mpu_synth_operations[2];
-static struct midi_operations  wf_mpu_midi_operations[2];
-
-static struct midi_operations wf_mpu_midi_proto =
-{
-	.owner		= THIS_MODULE,
-	.info		= {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
-	.in_info	= {0},   /* in_info */
-	.open		= wf_mpu_open,
-	.close		= wf_mpu_close,
-	.ioctl		= wf_mpu_ioctl,
-	.outputc	= wf_mpu_out,
-	.start_read	= wf_mpu_start_read,
-	.end_read	= wf_mpu_end_read,
-	.buffer_status	= wf_mpu_buffer_status,
-};
-
-static struct synth_info wf_mpu_synth_info_proto =
-{"WaveFront MPU-401 interface", 0,
- SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
-
-static struct synth_info wf_mpu_synth_info[2];
-
-static int
-wf_mpu_synth_ioctl (int dev, unsigned int cmd, void __user *arg)
-{
-	int             midi_dev;
-	int index;
-
-	midi_dev = synth_devs[dev]->midi_dev;
-
-	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
-		return -(ENXIO);
-
-	if (midi_dev == phys_dev->devno) {
-		index = 0;
-	} else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
-		index = 1;
-	} else {
-		return -(EINVAL);
-	}
-
-	switch (cmd) {
-
-	case SNDCTL_SYNTH_INFO:
-		if (copy_to_user(arg,
-			      &wf_mpu_synth_info[index],
-			      sizeof (struct synth_info)))
-			return -EFAULT;
-		return 0;
-	
-	case SNDCTL_SYNTH_MEMAVL:
-		return 0x7fffffff;
-	
-	default:
-		return -EINVAL;
-	}
-}
-
-static int
-wf_mpu_synth_open (int dev, int mode)
-{
-	int             midi_dev;
-	struct wf_mpu_config *devc;
-
-	midi_dev = synth_devs[dev]->midi_dev;
-
-	if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) {
-		return -(ENXIO);
-	}
-  
-	if (phys_dev->devno == midi_dev) {
-		devc = phys_dev;
-	} else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
-		devc = virt_dev;
-	} else {
-		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
-		return -(EINVAL);
-	}
-
-	if (devc->opened) {
-		return -(EBUSY);
-	}
-  
-	devc->mode = MODE_SYNTH;
-	devc->synthno = dev;
-	devc->opened = mode;
-	devc->inputintr = NULL;
-	return 0;
-}
-
-static void
-wf_mpu_synth_close (int dev)
-{
-	int             midi_dev;
-	struct wf_mpu_config *devc;
-
-	midi_dev = synth_devs[dev]->midi_dev;
-
-	if (phys_dev->devno == midi_dev) {
-		devc = phys_dev;
-	} else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
-		devc = virt_dev;
-	} else {
-		printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
-		return;
-	}
-
-	devc->inputintr = NULL;
-	devc->opened = 0;
-	devc->mode = 0;
-}
-
-#define _MIDI_SYNTH_C_
-#define MIDI_SYNTH_NAME	"WaveFront (MIDI)"
-#define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-static struct synth_operations wf_mpu_synth_proto =
-{
-	.owner		= THIS_MODULE,
-	.id		= "WaveFront (ICS2115)",
-	.info		= NULL,  /* info field, filled in during configuration */
-	.midi_dev	= 0,     /* MIDI dev XXX should this be -1 ? */
-	.synth_type	= SYNTH_TYPE_MIDI,
-	.synth_subtype	= SAMPLE_TYPE_WAVEFRONT,
-	.open		= wf_mpu_synth_open,
-	.close		= wf_mpu_synth_close,
-	.ioctl		= wf_mpu_synth_ioctl,
-	.kill_note	= midi_synth_kill_note,
-	.start_note	= midi_synth_start_note,
-	.set_instr	= midi_synth_set_instr,
-	.reset		= midi_synth_reset,
-	.hw_control	= midi_synth_hw_control,
-	.load_patch	= midi_synth_load_patch,
-	.aftertouch	= midi_synth_aftertouch,
-	.controller	= midi_synth_controller,
-	.panning	= midi_synth_panning,
-	.bender		= midi_synth_bender,
-	.setup_voice	= midi_synth_setup_voice,
-	.send_sysex	= midi_synth_send_sysex
-};
-
-static int
-config_wf_mpu (struct wf_mpu_config *dev)
-
-{
-	int is_external;
-	char *name;
-	int index;
-
-	if (dev == phys_dev) {
-		name = "WaveFront internal MIDI";
-		is_external = 0;
-		index = 0;
-		memcpy ((char *) &wf_mpu_synth_operations[index],
-			(char *) &wf_mpu_synth_proto,
-			sizeof (struct synth_operations));
-	} else {
-		name = "WaveFront external MIDI";
-		is_external = 1;
-		index = 1;
-		/* no synth operations for an external MIDI interface */
-	}
-
-	memcpy ((char *) &wf_mpu_synth_info[dev->devno],
-		(char *) &wf_mpu_synth_info_proto,
-		sizeof (struct synth_info));
-
-	strcpy (wf_mpu_synth_info[index].name, name);
-
-	wf_mpu_synth_operations[index].midi_dev = dev->devno;
-	wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
-
-	memcpy ((char *) &wf_mpu_midi_operations[index],
-		(char *) &wf_mpu_midi_proto,
-		sizeof (struct midi_operations));
-  
-	if (is_external) {
-		wf_mpu_midi_operations[index].converter = NULL;
-	} else {
-		wf_mpu_midi_operations[index].converter =
-			&wf_mpu_synth_operations[index];
-	}
-
-	strcpy (wf_mpu_midi_operations[index].info.name, name);
-
-	midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
-	midi_devs[dev->devno]->in_info.m_busy = 0;
-	midi_devs[dev->devno]->in_info.m_state = MST_INIT;
-	midi_devs[dev->devno]->in_info.m_ptr = 0;
-	midi_devs[dev->devno]->in_info.m_left = 0;
-	midi_devs[dev->devno]->in_info.m_prev_status = 0;
-
-	devs[index].opened = 0;
-	devs[index].mode = 0;
-
-	return (0);
-}
-
-int virtual_midi_enable (void)
-
-{
-	if ((virt_dev->devno < 0) &&
-	    (virt_dev->devno = sound_alloc_mididev()) == -1) {
-		printk (KERN_ERR
-			"WF-MPU: too many midi devices detected\n");
-		return -1;
-	}
-
-	config_wf_mpu (virt_dev);
-
-	phys_dev->isvirtual = 1;
-	return virt_dev->devno;
-}
-
-int
-virtual_midi_disable (void)
-
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&lock,flags);
-
-	wf_mpu_close (virt_dev->devno);
-	/* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
-	phys_dev->isvirtual = 0;
-
-	spin_unlock_irqrestore(&lock,flags);
-
-	return 0;
-}
-
-int __init detect_wf_mpu (int irq, int io_base)
-{
-	if (!request_region(io_base, 2, "wavefront midi")) {
-		printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
-			io_base);
-		return -1;
-	}
-
-	phys_dev->base = io_base;
-	phys_dev->irq = irq;
-	phys_dev->devno = -1;
-	virt_dev->devno = -1;
-
-	return 0;
-}
-
-int __init install_wf_mpu (void)
-{
-	if ((phys_dev->devno = sound_alloc_mididev()) < 0){
-
-		printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
-		release_region(phys_dev->base, 2);
-		return -1;
-	}
-
-	phys_dev->isvirtual = 0;
-
-	if (config_wf_mpu (phys_dev)) {
-
-		printk (KERN_WARNING
-			"WF-MPU: configuration for MIDI device %d failed\n",
-			phys_dev->devno);
-		sound_unload_mididev (phys_dev->devno);
-
-	}
-
-	/* OK, now we're configured to handle an interrupt ... */
-
-	if (request_irq (phys_dev->irq, wf_mpuintr, IRQF_DISABLED|IRQF_SHARED,
-			 "wavefront midi", phys_dev) < 0) {
-
-		printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
-			phys_dev->irq);
-		return -1;
-
-	}
-
-	/* This being a WaveFront (ICS-2115) emulated MPU-401, we have
-	   to switch it into UART (dumb) mode, because otherwise, it
-	   won't do anything at all.
-	*/
-  
-	start_uart_mode ();
-
-	return phys_dev->devno;
-}
- 
-void
-uninstall_wf_mpu (void)
-
-{
-	release_region (phys_dev->base, 2); 
-	free_irq (phys_dev->irq, phys_dev);
-	sound_unload_mididev (phys_dev->devno);
-
-	if (virt_dev->devno >= 0) {
-		sound_unload_mididev (virt_dev->devno);
-	}
-}
-
-static void
-start_uart_mode (void)
-
-{
-	int             ok, i;
-	unsigned long   flags;
-
-	spin_lock_irqsave(&lock,flags);
-
-	/* XXX fix me */
-
-	for (i = 0; i < 30000 && !output_ready (); i++);
-
-	outb (UART_MODE_ON, COMDPORT(phys_dev));
-
-	for (ok = 0, i = 50000; i > 0 && !ok; i--) {
-		if (input_avail ()) {
-			if (read_data () == MPU_ACK) {
-				ok = 1;
-			}
-		}
-	}
-
-	spin_unlock_irqrestore(&lock,flags);
-}
-#endif
diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c
deleted file mode 100644
index 6e22472..0000000
--- a/sound/oss/ymfpci.c
+++ /dev/null
@@ -1,2692 +0,0 @@
-/*
- *  Copyright 1999 Jaroslav Kysela <perex@suse.cz>
- *  Copyright 2000 Alan Cox <alan@redhat.com>
- *  Copyright 2001 Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
- *  Copyright 2002 Pete Zaitcev <zaitcev@yahoo.com>
- *
- *  Yamaha YMF7xx driver.
- *
- *  This code is a result of high-speed collision
- *  between ymfpci.c of ALSA and cs46xx.c of Linux.
- *  -- Pete Zaitcev <zaitcev@yahoo.com>; 2000/09/18
- *
- *   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.
- *
- * TODO:
- *  - Use P44Slot for 44.1 playback (beware of idle buzzing in P44Slot).
- *  - 96KHz playback for DVD - use pitch of 2.0.
- *  - Retain DMA buffer on close, do not wait the end of frame.
- *  - Resolve XXX tagged questions.
- *  - Cannot play 5133Hz.
- *  - 2001/01/07 Consider if we can remove voice_lock, like so:
- *     : Allocate/deallocate voices in open/close under semafore.
- *     : We access voices in interrupt, that only for pcms that open.
- *    voice_lock around playback_prepare closes interrupts for insane duration.
- *  - Revisit the way voice_alloc is done - too confusing, overcomplicated.
- *    Should support various channel types, however.
- *  - Remove prog_dmabuf from read/write, leave it in open.
- *  - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
- *    native synthesizer through a playback slot.
- *  - 2001/11/29 ac97_save_state
- *    Talk to Kai to remove ac97_save_state before it's too late!
- *  - Second AC97
- *  - Restore S/PDIF - Toshibas have it.
- *
- * Kai used pci_alloc_consistent for DMA buffer, which sounds a little
- * unconventional. However, given how small our fragments can be,
- * a little uncached access is perhaps better than endless flushing.
- * On i386 and other I/O-coherent architectures pci_alloc_consistent
- * is entirely harmless.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/sound.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-# include "sound_config.h"
-# include "mpu401.h"
-#endif
-#include "ymfpci.h"
-
-/*
- * I do not believe in debug levels as I never can guess what
- * part of the code is going to be problematic in the future.
- * Don't forget to run your klogd with -c 8.
- *
- * Example (do not remove):
- * #define YMFDBG(fmt, arg...)  do{ printk(KERN_DEBUG fmt, ##arg); }while(0)
- */
-#define YMFDBGW(fmt, arg...)  /* */	/* write counts */
-#define YMFDBGI(fmt, arg...)  /* */	/* interrupts */
-#define YMFDBGX(fmt, arg...)  /* */	/* ioctl */
-
-static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
-static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice);
-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank);
-static int ymf_playback_prepare(struct ymf_state *state);
-static int ymf_capture_prepare(struct ymf_state *state);
-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit);
-
-static void ymfpci_aclink_reset(struct pci_dev * pci);
-static void ymfpci_disable_dsp(ymfpci_t *unit);
-static void ymfpci_download_image(ymfpci_t *codec);
-static void ymf_memload(ymfpci_t *unit);
-
-static DEFINE_SPINLOCK(ymf_devs_lock);
-static LIST_HEAD(ymf_devs);
-
-/*
- *  constants
- */
-
-static struct pci_device_id ymf_id_tbl[] = {
-#define DEV(dev, data) \
-	{ PCI_VENDOR_ID_YAMAHA, dev, PCI_ANY_ID, PCI_ANY_ID, 0, 0, \
-		(unsigned long)data }
-	DEV (PCI_DEVICE_ID_YAMAHA_724,  "YMF724"),
-	DEV (PCI_DEVICE_ID_YAMAHA_724F, "YMF724F"),
-	DEV (PCI_DEVICE_ID_YAMAHA_740,  "YMF740"),
-	DEV (PCI_DEVICE_ID_YAMAHA_740C, "YMF740C"),
-	DEV (PCI_DEVICE_ID_YAMAHA_744,  "YMF744"),
-	DEV (PCI_DEVICE_ID_YAMAHA_754,  "YMF754"),
-#undef DEV
-	{ }
-};
-MODULE_DEVICE_TABLE(pci, ymf_id_tbl);
-
-/*
- *  common I/O routines
- */
-
-static inline void ymfpci_writeb(ymfpci_t *codec, u32 offset, u8 val)
-{
-	writeb(val, codec->reg_area_virt + offset);
-}
-
-static inline u16 ymfpci_readw(ymfpci_t *codec, u32 offset)
-{
-	return readw(codec->reg_area_virt + offset);
-}
-
-static inline void ymfpci_writew(ymfpci_t *codec, u32 offset, u16 val)
-{
-	writew(val, codec->reg_area_virt + offset);
-}
-
-static inline u32 ymfpci_readl(ymfpci_t *codec, u32 offset)
-{
-	return readl(codec->reg_area_virt + offset);
-}
-
-static inline void ymfpci_writel(ymfpci_t *codec, u32 offset, u32 val)
-{
-	writel(val, codec->reg_area_virt + offset);
-}
-
-static int ymfpci_codec_ready(ymfpci_t *codec, int secondary, int sched)
-{
-	signed long end_time;
-	u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
-	
-	end_time = jiffies + 3 * (HZ / 4);
-	do {
-		if ((ymfpci_readw(codec, reg) & 0x8000) == 0)
-			return 0;
-		if (sched) {
-			set_current_state(TASK_UNINTERRUPTIBLE);
-			schedule_timeout(1);
-		}
-	} while (end_time - (signed long)jiffies >= 0);
-	printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
-	    secondary, ymfpci_readw(codec, reg));
-	return -EBUSY;
-}
-
-static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val)
-{
-	ymfpci_t *codec = dev->private_data;
-	u32 cmd;
-
-	spin_lock(&codec->ac97_lock);
-	/* XXX Do make use of dev->id */
-	ymfpci_codec_ready(codec, 0, 0);
-	cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val;
-	ymfpci_writel(codec, YDSXGR_AC97CMDDATA, cmd);
-	spin_unlock(&codec->ac97_lock);
-}
-
-static u16 _ymfpci_codec_read(ymfpci_t *unit, u8 reg)
-{
-	int i;
-
-	if (ymfpci_codec_ready(unit, 0, 0))
-		return ~0;
-	ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
-	if (ymfpci_codec_ready(unit, 0, 0))
-		return ~0;
-	if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
-		for (i = 0; i < 600; i++)
-			ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
-	}
-	return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
-}
-
-static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
-{
-	ymfpci_t *unit = dev->private_data;
-	u16 ret;
-	
-	spin_lock(&unit->ac97_lock);
-	ret = _ymfpci_codec_read(unit, reg);
-	spin_unlock(&unit->ac97_lock);
-	
-	return ret;
-}
-
-/*
- *  Misc routines
- */
-
-/*
- * Calculate the actual sampling rate relatetively to the base clock (48kHz).
- */
-static u32 ymfpci_calc_delta(u32 rate)
-{
-	switch (rate) {
-	case 8000:	return 0x02aaab00;
-	case 11025:	return 0x03accd00;
-	case 16000:	return 0x05555500;
-	case 22050:	return 0x07599a00;
-	case 32000:	return 0x0aaaab00;
-	case 44100:	return 0x0eb33300;
-	default:	return ((rate << 16) / 48000) << 12;
-	}
-}
-
-static u32 def_rate[8] = {
-	100, 2000, 8000, 11025, 16000, 22050, 32000, 48000
-};
-
-static u32 ymfpci_calc_lpfK(u32 rate)
-{
-	u32 i;
-	static u32 val[8] = {
-		0x00570000, 0x06AA0000, 0x18B20000, 0x20930000,
-		0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000
-	};
-	
-	if (rate == 44100)
-		return 0x40000000;	/* FIXME: What's the right value? */
-	for (i = 0; i < 8; i++)
-		if (rate <= def_rate[i])
-			return val[i];
-	return val[0];
-}
-
-static u32 ymfpci_calc_lpfQ(u32 rate)
-{
-	u32 i;
-	static u32 val[8] = {
-		0x35280000, 0x34A70000, 0x32020000, 0x31770000,
-		0x31390000, 0x31C90000, 0x33D00000, 0x40000000
-	};
-	
-	if (rate == 44100)
-		return 0x370A0000;
-	for (i = 0; i < 8; i++)
-		if (rate <= def_rate[i])
-			return val[i];
-	return val[0];
-}
-
-static u32 ymf_calc_lend(u32 rate)
-{
-	return (rate * YMF_SAMPF) / 48000;
-}
-
-/*
- * We ever allow only a few formats, but let's be generic, for smaller surprise.
- */
-static int ymf_pcm_format_width(int format)
-{
-	static int mask16 = AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE;
-
-	if ((format & (format-1)) != 0) {
-		printk(KERN_ERR "ymfpci: format 0x%x is not a power of 2\n", format);
-		return 8;
-	}
-
-	if (format == AFMT_IMA_ADPCM) return 4;
-	if ((format & mask16) != 0) return 16;
-	return 8;
-}
-
-static void ymf_pcm_update_shift(struct ymf_pcm_format *f)
-{
-	f->shift = 0;
-	if (f->voices == 2)
-		f->shift++;
-	if (ymf_pcm_format_width(f->format) == 16)
-		f->shift++;
-}
-
-/* Are you sure 32K is not too much? See if mpg123 skips on loaded systems. */
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/*
- * Allocate DMA buffer
- */
-static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
-{
-	void *rawbuf = NULL;
-	dma_addr_t dma_addr;
-	int order;
-	struct page *map, *mapend;
-
-	/* alloc as big a chunk as we can */
-	for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
-		rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr);
-		if (rawbuf)
-			break;
-	}
-	if (!rawbuf)
-		return -ENOMEM;
-
-#if 0
-	printk(KERN_DEBUG "ymfpci: allocated %ld (order = %d) bytes at %p\n",
-	       PAGE_SIZE << order, order, rawbuf);
-#endif
-
-	dmabuf->ready  = dmabuf->mapped = 0;
-	dmabuf->rawbuf = rawbuf;
-	dmabuf->dma_addr = dma_addr;
-	dmabuf->buforder = order;
-
-	/* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
-	mapend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
-	for (map = virt_to_page(rawbuf); map <= mapend; map++)
-		set_bit(PG_reserved, &map->flags);
-
-	return 0;
-}
-
-/*
- * Free DMA buffer
- */
-static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
-{
-	struct page *map, *mapend;
-
-	if (dmabuf->rawbuf) {
-		/* undo marking the pages as reserved */
-		mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
-		for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
-			clear_bit(PG_reserved, &map->flags);
-
-		pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder,
-		    dmabuf->rawbuf, dmabuf->dma_addr);
-	}
-	dmabuf->rawbuf = NULL;
-	dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct ymf_state *state, int rec)
-{
-	struct ymf_dmabuf *dmabuf;
-	int w_16;
-	unsigned bufsize;
-	unsigned long flags;
-	int redzone, redfrags;
-	int ret;
-
-	w_16 = ymf_pcm_format_width(state->format.format) == 16;
-	dmabuf = rec ? &state->rpcm.dmabuf : &state->wpcm.dmabuf;
-
-	spin_lock_irqsave(&state->unit->reg_lock, flags);
-	dmabuf->hwptr = dmabuf->swptr = 0;
-	dmabuf->total_bytes = 0;
-	dmabuf->count = 0;
-	spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-
-	/* allocate DMA buffer if not allocated yet */
-	if (!dmabuf->rawbuf)
-		if ((ret = alloc_dmabuf(state->unit, dmabuf)))
-			return ret;
-
-	/*
-	 * Create fake fragment sizes and numbers for OSS ioctls.
-	 * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT.
-	 */
-	bufsize = PAGE_SIZE << dmabuf->buforder;
-	/* By default we give 4 big buffers. */
-	dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2);
-	if (dmabuf->ossfragshift > 3 &&
-	    dmabuf->ossfragshift < dmabuf->fragshift) {
-		/* If OSS set smaller fragments, give more smaller buffers. */
-		dmabuf->fragshift = dmabuf->ossfragshift;
-	}
-	dmabuf->fragsize = 1 << dmabuf->fragshift;
-
-	dmabuf->numfrag = bufsize >> dmabuf->fragshift;
-	dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
-
-	if (dmabuf->ossmaxfrags >= 2) {
-		redzone = ymf_calc_lend(state->format.rate);
-		redzone <<= state->format.shift;
-		redzone *= 3;
-		redfrags = (redzone + dmabuf->fragsize-1) >> dmabuf->fragshift;
-
-		if (dmabuf->ossmaxfrags + redfrags < dmabuf->numfrag) {
-			dmabuf->numfrag = dmabuf->ossmaxfrags + redfrags;
-			dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
-		}
-	}
-
-	memset(dmabuf->rawbuf, w_16 ? 0 : 0x80, dmabuf->dmasize);
-
-	/*
-	 *	Now set up the ring 
-	 */
-
-	/* XXX   ret = rec? cap_pre(): pbk_pre();  */
-	spin_lock_irqsave(&state->unit->voice_lock, flags);
-	if (rec) {
-		if ((ret = ymf_capture_prepare(state)) != 0) {
-			spin_unlock_irqrestore(&state->unit->voice_lock, flags);
-			return ret;
-		}
-	} else {
-		if ((ret = ymf_playback_prepare(state)) != 0) {
-			spin_unlock_irqrestore(&state->unit->voice_lock, flags);
-			return ret;
-		}
-	}
-	spin_unlock_irqrestore(&state->unit->voice_lock, flags);
-
-	/* set the ready flag for the dma buffer (this comment is not stupid) */
-	dmabuf->ready = 1;
-
-#if 0
-	printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
-	    " numfrag %d fragsize %d dmasize %d\n",
-	       state->format.rate, state->format.format, dmabuf->numfrag,
-	       dmabuf->fragsize, dmabuf->dmasize);
-#endif
-
-	return 0;
-}
-
-static void ymf_start_dac(struct ymf_state *state)
-{
-	ymf_playback_trigger(state->unit, &state->wpcm, 1);
-}
-
-// static void ymf_start_adc(struct ymf_state *state)
-// {
-// 	ymf_capture_trigger(state->unit, &state->rpcm, 1);
-// }
-
-/*
- * Wait until output is drained.
- * This does not kill the hardware for the sake of ioctls.
- */
-static void ymf_wait_dac(struct ymf_state *state)
-{
-	struct ymf_unit *unit = state->unit;
-	struct ymf_pcm *ypcm = &state->wpcm;
-	DECLARE_WAITQUEUE(waita, current);
-	unsigned long flags;
-
-	add_wait_queue(&ypcm->dmabuf.wait, &waita);
-
-	spin_lock_irqsave(&unit->reg_lock, flags);
-	if (ypcm->dmabuf.count != 0 && !ypcm->running) {
-		ymf_playback_trigger(unit, ypcm, 1);
-	}
-
-#if 0
-	if (file->f_flags & O_NONBLOCK) {
-		/*
-		 * XXX Our  mistake is to attach DMA buffer to state
-		 * rather than to some per-device structure.
-		 * Cannot skip waiting, can only make it shorter.
-		 */
-	}
-#endif
-
-	set_current_state(TASK_UNINTERRUPTIBLE);
-	while (ypcm->running) {
-		spin_unlock_irqrestore(&unit->reg_lock, flags);
-		schedule();
-		spin_lock_irqsave(&unit->reg_lock, flags);
-		set_current_state(TASK_UNINTERRUPTIBLE);
-	}
-	spin_unlock_irqrestore(&unit->reg_lock, flags);
-
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&ypcm->dmabuf.wait, &waita);
-
-	/*
-	 * This function may take up to 4 seconds to reach this point
-	 * (32K circular buffer, 8000 Hz). User notices.
-	 */
-}
-
-/* Can just stop, without wait. Or can we? */
-static void ymf_stop_adc(struct ymf_state *state)
-{
-	struct ymf_unit *unit = state->unit;
-	unsigned long flags;
-
-	spin_lock_irqsave(&unit->reg_lock, flags);
-	ymf_capture_trigger(unit, &state->rpcm, 0);
-	spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-/*
- *  Hardware start management
- */
-
-static void ymfpci_hw_start(ymfpci_t *unit)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&unit->reg_lock, flags);
-	if (unit->start_count++ == 0) {
-		ymfpci_writel(unit, YDSXGR_MODE,
-		    ymfpci_readl(unit, YDSXGR_MODE) | 3);
-		unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
-	}
-	spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-static void ymfpci_hw_stop(ymfpci_t *unit)
-{
-	unsigned long flags;
-	long timeout = 1000;
-
-	spin_lock_irqsave(&unit->reg_lock, flags);
-	if (--unit->start_count == 0) {
-		ymfpci_writel(unit, YDSXGR_MODE,
-		    ymfpci_readl(unit, YDSXGR_MODE) & ~3);
-		while (timeout-- > 0) {
-			if ((ymfpci_readl(unit, YDSXGR_STATUS) & 2) == 0)
-				break;
-		}
-	}
-	spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-/*
- *  Playback voice management
- */
-
-static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[])
-{
-	ymfpci_voice_t *voice, *voice2;
-	int idx;
-
-	for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) {
-		voice = &codec->voices[idx];
-		voice2 = pair ? &codec->voices[idx+1] : NULL;
-		if (voice->use || (voice2 && voice2->use))
-			continue;
-		voice->use = 1;
-		if (voice2)
-			voice2->use = 1;
-		switch (type) {
-		case YMFPCI_PCM:
-			voice->pcm = 1;
-			if (voice2)
-				voice2->pcm = 1;
-			break;
-		case YMFPCI_SYNTH:
-			voice->synth = 1;
-			break;
-		case YMFPCI_MIDI:
-			voice->midi = 1;
-			break;
-		}
-		ymfpci_hw_start(codec);
-		rvoice[0] = voice;
-		if (voice2) {
-			ymfpci_hw_start(codec);
-			rvoice[1] = voice2;
-		}
-		return 0;
-	}
-	return -EBUSY;	/* Your audio channel is open by someone else. */
-}
-
-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice)
-{
-	ymfpci_hw_stop(unit);
-	pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
-	pvoice->ypcm = NULL;
-}
-
-/*
- */
-
-static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
-{
-	struct ymf_pcm *ypcm;
-	int redzone;
-	int pos, delta, swptr;
-	int played, distance;
-	struct ymf_state *state;
-	struct ymf_dmabuf *dmabuf;
-	char silence;
-
-	if ((ypcm = voice->ypcm) == NULL) {
-		return;
-	}
-	if ((state = ypcm->state) == NULL) {
-		ypcm->running = 0;	// lock it
-		return;
-	}
-	dmabuf = &ypcm->dmabuf;
-	spin_lock(&codec->reg_lock);
-	if (ypcm->running) {
-		YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
-		   voice->number, codec->active_bank, dmabuf->count,
-		   le32_to_cpu(voice->bank[0].start),
-		   le32_to_cpu(voice->bank[1].start));
-		silence = (ymf_pcm_format_width(state->format.format) == 16) ?
-		    0 : 0x80;
-		/* We need actual left-hand-side redzone size here. */
-		redzone = ymf_calc_lend(state->format.rate);
-		redzone <<= (state->format.shift + 1);
-		swptr = dmabuf->swptr;
-
-		pos = le32_to_cpu(voice->bank[codec->active_bank].start);
-		pos <<= state->format.shift;
-		if (pos < 0 || pos >= dmabuf->dmasize) {	/* ucode bug */
-			printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
-			    codec->dev_audio, voice->number,
-			    dmabuf->hwptr, pos, dmabuf->dmasize);
-			pos = 0;
-		}
-		if (pos < dmabuf->hwptr) {
-			delta = dmabuf->dmasize - dmabuf->hwptr;
-			memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
-			delta += pos;
-			memset(dmabuf->rawbuf, silence, pos);
-		} else {
-			delta = pos - dmabuf->hwptr;
-			memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
-		}
-		dmabuf->hwptr = pos;
-
-		if (dmabuf->count == 0) {
-			printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
-			    codec->dev_audio, voice->number, dmabuf->hwptr);
-			ymf_playback_trigger(codec, ypcm, 0);
-		}
-
-		if (swptr <= pos) {
-			distance = pos - swptr;
-		} else {
-			distance = dmabuf->dmasize - (swptr - pos);
-		}
-		if (distance < redzone) {
-			/*
-			 * hwptr inside redzone => DMA ran out of samples.
-			 */
-			if (delta < dmabuf->count) {
-				/*
-				 * Lost interrupt or other screwage.
-				 */
-				printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
-				    " hwptr %d swptr %d distance %d count %d\n",
-				    codec->dev_audio, voice->number, delta,
-				    dmabuf->hwptr, swptr, distance, dmabuf->count);
-			} else {
-				/*
-				 * Normal end of DMA.
-				 */
-				YMFDBGI("ymfpci%d: %d: done: delta %d"
-				    " hwptr %d swptr %d distance %d count %d\n",
-				    codec->dev_audio, voice->number, delta,
-				    dmabuf->hwptr, swptr, distance, dmabuf->count);
-			}
-			played = dmabuf->count;
-			if (ypcm->running) {
-				ymf_playback_trigger(codec, ypcm, 0);
-			}
-		} else {
-			/*
-			 * hwptr is chipping away towards a remote swptr.
-			 * Calculate other distance and apply it to count.
-			 */
-			if (swptr >= pos) {
-				distance = swptr - pos;
-			} else {
-				distance = dmabuf->dmasize - (pos - swptr);
-			}
-			if (distance < dmabuf->count) {
-				played = dmabuf->count - distance;
-			} else {
-				played = 0;
-			}
-		}
-
-		dmabuf->total_bytes += played;
-		dmabuf->count -= played;
-		if (dmabuf->count < dmabuf->dmasize / 2) {
-			wake_up(&dmabuf->wait);
-		}
-	}
-	spin_unlock(&codec->reg_lock);
-}
-
-static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap)
-{
-	struct ymf_pcm *ypcm;
-	int redzone;
-	struct ymf_state *state;
-	struct ymf_dmabuf *dmabuf;
-	int pos, delta;
-	int cnt;
-
-	if ((ypcm = cap->ypcm) == NULL) {
-		return;
-	}
-	if ((state = ypcm->state) == NULL) {
-		ypcm->running = 0;	// lock it
-		return;
-	}
-	dmabuf = &ypcm->dmabuf;
-	spin_lock(&unit->reg_lock);
-	if (ypcm->running) {
-		redzone = ymf_calc_lend(state->format.rate);
-		redzone <<= (state->format.shift + 1);
-
-		pos = le32_to_cpu(cap->bank[unit->active_bank].start);
-		// pos <<= state->format.shift;
-		if (pos < 0 || pos >= dmabuf->dmasize) {	/* ucode bug */
-			printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
-			    unit->dev_audio, ypcm->capture_bank_number,
-			    dmabuf->hwptr, pos, dmabuf->dmasize);
-			pos = 0;
-		}
-		if (pos < dmabuf->hwptr) {
-			delta = dmabuf->dmasize - dmabuf->hwptr;
-			delta += pos;
-		} else {
-			delta = pos - dmabuf->hwptr;
-		}
-		dmabuf->hwptr = pos;
-
-		cnt = dmabuf->count;
-		cnt += delta;
-		if (cnt + redzone > dmabuf->dmasize) {
-			/* Overflow - bump swptr */
-			dmabuf->count = dmabuf->dmasize - redzone;
-			dmabuf->swptr = dmabuf->hwptr + redzone;
-			if (dmabuf->swptr >= dmabuf->dmasize) {
-				dmabuf->swptr -= dmabuf->dmasize;
-			}
-		} else {
-			dmabuf->count = cnt;
-		}
-
-		dmabuf->total_bytes += delta;
-		if (dmabuf->count) {		/* && is_sleeping  XXX */
-			wake_up(&dmabuf->wait);
-		}
-	}
-	spin_unlock(&unit->reg_lock);
-}
-
-static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
-{
-
-	if (ypcm->voices[0] == NULL) {
-		return -EINVAL;
-	}
-	if (cmd != 0) {
-		codec->ctrl_playback[ypcm->voices[0]->number + 1] =
-		    cpu_to_le32(ypcm->voices[0]->bank_ba);
-		if (ypcm->voices[1] != NULL)
-			codec->ctrl_playback[ypcm->voices[1]->number + 1] =
-			    cpu_to_le32(ypcm->voices[1]->bank_ba);
-		ypcm->running = 1;
-	} else {
-		codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
-		if (ypcm->voices[1] != NULL)
-			codec->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
-		ypcm->running = 0;
-	}
-	return 0;
-}
-
-static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
-{
-	u32 tmp;
-
-	if (cmd != 0) {
-		tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);
-		ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
-		ypcm->running = 1;
-	} else {
-		tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);
-		ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
-		ypcm->running = 0;
-	}
-}
-
-static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices)
-{
-	struct ymf_unit *unit;
-	int err;
-
-	unit = ypcm->state->unit;
-	if (ypcm->voices[1] != NULL && voices < 2) {
-		ymfpci_voice_free(unit, ypcm->voices[1]);
-		ypcm->voices[1] = NULL;
-	}
-	if (voices == 1 && ypcm->voices[0] != NULL)
-		return 0;		/* already allocated */
-	if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL)
-		return 0;		/* already allocated */
-	if (voices > 1) {
-		if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {
-			ymfpci_voice_free(unit, ypcm->voices[0]);
-			ypcm->voices[0] = NULL;
-		}		
-		if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0)
-			return err;
-		ypcm->voices[0]->ypcm = ypcm;
-		ypcm->voices[1]->ypcm = ypcm;
-	} else {
-		if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0)
-			return err;
-		ypcm->voices[0]->ypcm = ypcm;
-	}
-	return 0;
-}
-
-static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
-    int rate, int w_16, unsigned long addr, unsigned int end, int spdif)
-{
-	u32 format;
-	u32 delta = ymfpci_calc_delta(rate);
-	u32 lpfQ = ymfpci_calc_lpfQ(rate);
-	u32 lpfK = ymfpci_calc_lpfK(rate);
-	ymfpci_playback_bank_t *bank;
-	int nbank;
-
-	/*
-	 * The gain is a floating point number. According to the manual,
-	 * bit 31 indicates a sign bit, bit 30 indicates an integer part,
-	 * and bits [29:15] indicate a decimal fraction part. Thus,
-	 * for a gain of 1.0 the constant of 0x40000000 is loaded.
-	 */
-	unsigned default_gain = cpu_to_le32(0x40000000);
-
-	format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
-	if (stereo)
-		end >>= 1;
-	if (w_16)
-		end >>= 1;
-	for (nbank = 0; nbank < 2; nbank++) {
-		bank = &voice->bank[nbank];
-		bank->format = cpu_to_le32(format);
-		bank->loop_default = 0;	/* 0-loops forever, otherwise count */
-		bank->base = cpu_to_le32(addr);
-		bank->loop_start = 0;
-		bank->loop_end = cpu_to_le32(end);
-		bank->loop_frac = 0;
-		bank->eg_gain_end = default_gain;
-		bank->lpfQ = cpu_to_le32(lpfQ);
-		bank->status = 0;
-		bank->num_of_frames = 0;
-		bank->loop_count = 0;
-		bank->start = 0;
-		bank->start_frac = 0;
-		bank->delta =
-		bank->delta_end = cpu_to_le32(delta);
-		bank->lpfK =
-		bank->lpfK_end = cpu_to_le32(lpfK);
-		bank->eg_gain = default_gain;
-		bank->lpfD1 =
-		bank->lpfD2 = 0;
-
-		bank->left_gain = 
-		bank->right_gain =
-		bank->left_gain_end =
-		bank->right_gain_end =
-		bank->eff1_gain =
-		bank->eff2_gain =
-		bank->eff3_gain =
-		bank->eff1_gain_end =
-		bank->eff2_gain_end =
-		bank->eff3_gain_end = 0;
-
-		if (!stereo) {
-			if (!spdif) {
-				bank->left_gain = 
-				bank->right_gain =
-				bank->left_gain_end =
-				bank->right_gain_end = default_gain;
-			} else {
-				bank->eff2_gain =
-				bank->eff2_gain_end =
-				bank->eff3_gain =
-				bank->eff3_gain_end = default_gain;
-			}
-		} else {
-			if (!spdif) {
-				if ((voice->number & 1) == 0) {
-					bank->left_gain =
-					bank->left_gain_end = default_gain;
-				} else {
-					bank->format |= cpu_to_le32(1);
-					bank->right_gain =
-					bank->right_gain_end = default_gain;
-				}
-			} else {
-				if ((voice->number & 1) == 0) {
-					bank->eff2_gain =
-					bank->eff2_gain_end = default_gain;
-				} else {
-					bank->format |= cpu_to_le32(1);
-					bank->eff3_gain =
-					bank->eff3_gain_end = default_gain;
-				}
-			}
-		}
-	}
-}
-
-/*
- * XXX Capture channel allocation is entirely fake at the moment.
- * We use only one channel and mark it busy as required.
- */
-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank)
-{
-	struct ymf_capture *cap;
-	int cbank;
-
-	cbank = 1;		/* Only ADC slot is used for now. */
-	cap = &unit->capture[cbank];
-	if (cap->use)
-		return -EBUSY;
-	cap->use = 1;
-	*pbank = cbank;
-	return 0;
-}
-
-static int ymf_playback_prepare(struct ymf_state *state)
-{
-	struct ymf_pcm *ypcm = &state->wpcm;
-	int err, nvoice;
-
-	if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
-		/* Somebody started 32 mpg123's in parallel? */
-		printk(KERN_INFO "ymfpci%d: cannot allocate voice\n",
-		    state->unit->dev_audio);
-		return err;
-	}
-
-	for (nvoice = 0; nvoice < state->format.voices; nvoice++) {
-		ymf_pcm_init_voice(ypcm->voices[nvoice],
-		    state->format.voices == 2, state->format.rate,
-		    ymf_pcm_format_width(state->format.format) == 16,
-		    ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize,
-		    ypcm->spdif);
-	}
-	return 0;
-}
-
-static int ymf_capture_prepare(struct ymf_state *state)
-{
-	ymfpci_t *unit = state->unit;
-	struct ymf_pcm *ypcm = &state->rpcm;
-	ymfpci_capture_bank_t * bank;
-	/* XXX This is confusing, gotta rename one of them banks... */
-	int nbank;		/* flip-flop bank */
-	int cbank;		/* input [super-]bank */
-	struct ymf_capture *cap;
-	u32 rate, format;
-
-	if (ypcm->capture_bank_number == -1) {
-		if (ymf_capture_alloc(unit, &cbank) != 0)
-			return -EBUSY;
-
-		ypcm->capture_bank_number = cbank;
-
-		cap = &unit->capture[cbank];
-		cap->bank = unit->bank_capture[cbank][0];
-		cap->ypcm = ypcm;
-		ymfpci_hw_start(unit);
-	}
-
-	// ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream);
-	// frag_size is replaced with nonfragged byte-aligned rolling buffer
-	rate = ((48000 * 4096) / state->format.rate) - 1;
-	format = 0;
-	if (state->format.voices == 2)
-		format |= 2;
-	if (ymf_pcm_format_width(state->format.format) == 8)
-		format |= 1;
-	switch (ypcm->capture_bank_number) {
-	case 0:
-		ymfpci_writel(unit, YDSXGR_RECFORMAT, format);
-		ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate);
-		break;
-	case 1:
-		ymfpci_writel(unit, YDSXGR_ADCFORMAT, format);
-		ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate);
-		break;
-	}
-	for (nbank = 0; nbank < 2; nbank++) {
-		bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
-		bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr);
-		// bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
-		bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize);
-		bank->start = 0;
-		bank->num_of_loops = 0;
-	}
-#if 0 /* s/pdif */
-	if (state->digital.dig_valid)
-		/*state->digital.type == SND_PCM_DIG_AES_IEC958*/
-		ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS,
-		    state->digital.dig_status[0] | (state->digital.dig_status[1] << 8));
-#endif
-	return 0;
-}
-
-static irqreturn_t ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	ymfpci_t *codec = dev_id;
-	u32 status, nvoice, mode;
-	struct ymf_voice *voice;
-	struct ymf_capture *cap;
-
-	status = ymfpci_readl(codec, YDSXGR_STATUS);
-	if (status & 0x80000000) {
-		codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1;
-		spin_lock(&codec->voice_lock);
-		for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
-			voice = &codec->voices[nvoice];
-			if (voice->use)
-				ymf_pcm_interrupt(codec, voice);
-		}
-		for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
-			cap = &codec->capture[nvoice];
-			if (cap->use)
-				ymf_cap_interrupt(codec, cap);
-		}
-		spin_unlock(&codec->voice_lock);
-		spin_lock(&codec->reg_lock);
-		ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000);
-		mode = ymfpci_readl(codec, YDSXGR_MODE) | 2;
-		ymfpci_writel(codec, YDSXGR_MODE, mode);
-		spin_unlock(&codec->reg_lock);
-	}
-
-	status = ymfpci_readl(codec, YDSXGR_INTFLAG);
-	if (status & 1) {
-		/* timer handler */
-		ymfpci_writel(codec, YDSXGR_INTFLAG, ~0);
-	}
-	return IRQ_HANDLED;
-}
-
-static void ymf_pcm_free_substream(struct ymf_pcm *ypcm)
-{
-	unsigned long flags;
-	struct ymf_unit *unit;
-
-	unit = ypcm->state->unit;
-
-	if (ypcm->type == PLAYBACK_VOICE) {
-		spin_lock_irqsave(&unit->voice_lock, flags);
-		if (ypcm->voices[1])
-			ymfpci_voice_free(unit, ypcm->voices[1]);
-		if (ypcm->voices[0])
-			ymfpci_voice_free(unit, ypcm->voices[0]);
-		spin_unlock_irqrestore(&unit->voice_lock, flags);
-	} else {
-		if (ypcm->capture_bank_number != -1) {
-			unit->capture[ypcm->capture_bank_number].use = 0;
-			ypcm->capture_bank_number = -1;
-			ymfpci_hw_stop(unit);
-		}
-	}
-}
-
-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit)
-{
-	struct ymf_pcm *ypcm;
-	struct ymf_state *state;
-
-	if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) {
-		goto out0;
-	}
-	memset(state, 0, sizeof(struct ymf_state));
-
-	ypcm = &state->wpcm;
-	ypcm->state = state;
-	ypcm->type = PLAYBACK_VOICE;
-	ypcm->capture_bank_number = -1;
-	init_waitqueue_head(&ypcm->dmabuf.wait);
-
-	ypcm = &state->rpcm;
-	ypcm->state = state;
-	ypcm->type = CAPTURE_AC97;
-	ypcm->capture_bank_number = -1;
-	init_waitqueue_head(&ypcm->dmabuf.wait);
-
-	state->unit = unit;
-
-	state->format.format = AFMT_U8;
-	state->format.rate = 8000;
-	state->format.voices = 1;
-	ymf_pcm_update_shift(&state->format);
-
-	return state;
-
-out0:
-	return NULL;
-}
-
-/* AES/IEC958 channel status bits */
-#define SND_PCM_AES0_PROFESSIONAL	(1<<0)	/* 0 = consumer, 1 = professional */
-#define SND_PCM_AES0_NONAUDIO		(1<<1)	/* 0 = audio, 1 = non-audio */
-#define SND_PCM_AES0_PRO_EMPHASIS	(7<<2)	/* mask - emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_NOTID	(0<<2)	/* emphasis not indicated */
-#define SND_PCM_AES0_PRO_EMPHASIS_NONE	(1<<2)	/* none emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_5015	(3<<2)	/* 50/15us emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_CCITT	(7<<2)	/* CCITT J.17 emphasis */
-#define SND_PCM_AES0_PRO_FREQ_UNLOCKED	(1<<5)	/* source sample frequency: 0 = locked, 1 = unlocked */
-#define SND_PCM_AES0_PRO_FS		(3<<6)	/* mask - sample frequency */
-#define SND_PCM_AES0_PRO_FS_NOTID	(0<<6)	/* fs not indicated */
-#define SND_PCM_AES0_PRO_FS_44100	(1<<6)	/* 44.1kHz */
-#define SND_PCM_AES0_PRO_FS_48000	(2<<6)	/* 48kHz */
-#define SND_PCM_AES0_PRO_FS_32000	(3<<6)	/* 32kHz */
-#define SND_PCM_AES0_CON_NOT_COPYRIGHT	(1<<2)	/* 0 = copyright, 1 = not copyright */
-#define SND_PCM_AES0_CON_EMPHASIS	(7<<3)	/* mask - emphasis */
-#define SND_PCM_AES0_CON_EMPHASIS_NONE	(0<<3)	/* none emphasis */
-#define SND_PCM_AES0_CON_EMPHASIS_5015	(1<<3)	/* 50/15us emphasis */
-#define SND_PCM_AES0_CON_MODE		(3<<6)	/* mask - mode */
-#define SND_PCM_AES1_PRO_MODE		(15<<0)	/* mask - channel mode */
-#define SND_PCM_AES1_PRO_MODE_NOTID	(0<<0)	/* not indicated */
-#define SND_PCM_AES1_PRO_MODE_STEREOPHONIC (2<<0) /* stereophonic - ch A is left */
-#define SND_PCM_AES1_PRO_MODE_SINGLE	(4<<0)	/* single channel */
-#define SND_PCM_AES1_PRO_MODE_TWO	(8<<0)	/* two channels */
-#define SND_PCM_AES1_PRO_MODE_PRIMARY	(12<<0)	/* primary/secondary */
-#define SND_PCM_AES1_PRO_MODE_BYTE3	(15<<0)	/* vector to byte 3 */
-#define SND_PCM_AES1_PRO_USERBITS	(15<<4)	/* mask - user bits */
-#define SND_PCM_AES1_PRO_USERBITS_NOTID	(0<<4)	/* not indicated */
-#define SND_PCM_AES1_PRO_USERBITS_192	(8<<4)	/* 192-bit structure */
-#define SND_PCM_AES1_PRO_USERBITS_UDEF	(12<<4)	/* user defined application */
-#define SND_PCM_AES1_CON_CATEGORY	0x7f
-#define SND_PCM_AES1_CON_GENERAL	0x00
-#define SND_PCM_AES1_CON_EXPERIMENTAL	0x40
-#define SND_PCM_AES1_CON_SOLIDMEM_MASK	0x0f
-#define SND_PCM_AES1_CON_SOLIDMEM_ID	0x08
-#define SND_PCM_AES1_CON_BROADCAST1_MASK 0x07
-#define SND_PCM_AES1_CON_BROADCAST1_ID	0x04
-#define SND_PCM_AES1_CON_DIGDIGCONV_MASK 0x07
-#define SND_PCM_AES1_CON_DIGDIGCONV_ID	0x02
-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_ID 0x06
-#define SND_PCM_AES1_CON_ADC_MASK	0x1f
-#define SND_PCM_AES1_CON_ADC_ID		0x16
-#define SND_PCM_AES1_CON_BROADCAST2_MASK 0x0f
-#define SND_PCM_AES1_CON_BROADCAST2_ID	0x0e
-#define SND_PCM_AES1_CON_LASEROPT_MASK	0x07
-#define SND_PCM_AES1_CON_LASEROPT_ID	0x01
-#define SND_PCM_AES1_CON_MUSICAL_MASK	0x07
-#define SND_PCM_AES1_CON_MUSICAL_ID	0x05
-#define SND_PCM_AES1_CON_MAGNETIC_MASK	0x07
-#define SND_PCM_AES1_CON_MAGNETIC_ID	0x03
-#define SND_PCM_AES1_CON_IEC908_CD	(SND_PCM_AES1_CON_LASEROPT_ID|0x00)
-#define SND_PCM_AES1_CON_NON_IEC908_CD	(SND_PCM_AES1_CON_LASEROPT_ID|0x08)
-#define SND_PCM_AES1_CON_PCM_CODER	(SND_PCM_AES1_CON_DIGDIGCONV_ID|0x00)
-#define SND_PCM_AES1_CON_SAMPLER	(SND_PCM_AES1_CON_DIGDIGCONV_ID|0x20)
-#define SND_PCM_AES1_CON_MIXER		(SND_PCM_AES1_CON_DIGDIGCONV_ID|0x10)
-#define SND_PCM_AES1_CON_RATE_CONVERTER	(SND_PCM_AES1_CON_DIGDIGCONV_ID|0x18)
-#define SND_PCM_AES1_CON_SYNTHESIZER	(SND_PCM_AES1_CON_MUSICAL_ID|0x00)
-#define SND_PCM_AES1_CON_MICROPHONE	(SND_PCM_AES1_CON_MUSICAL_ID|0x08)
-#define SND_PCM_AES1_CON_DAT		(SND_PCM_AES1_CON_MAGNETIC_ID|0x00)
-#define SND_PCM_AES1_CON_VCR		(SND_PCM_AES1_CON_MAGNETIC_ID|0x08)
-#define SND_PCM_AES1_CON_ORIGINAL	(1<<7)	/* this bits depends on the category code */
-#define SND_PCM_AES2_PRO_SBITS		(7<<0)	/* mask - sample bits */
-#define SND_PCM_AES2_PRO_SBITS_20	(2<<0)	/* 20-bit - coordination */
-#define SND_PCM_AES2_PRO_SBITS_24	(4<<0)	/* 24-bit - main audio */
-#define SND_PCM_AES2_PRO_SBITS_UDEF	(6<<0)	/* user defined application */
-#define SND_PCM_AES2_PRO_WORDLEN	(7<<3)	/* mask - source word length */
-#define SND_PCM_AES2_PRO_WORDLEN_NOTID	(0<<3)	/* not indicated */
-#define SND_PCM_AES2_PRO_WORDLEN_22_18	(2<<3)	/* 22-bit or 18-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_23_19	(4<<3)	/* 23-bit or 19-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_24_20	(5<<3)	/* 24-bit or 20-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_20_16	(6<<3)	/* 20-bit or 16-bit */
-#define SND_PCM_AES2_CON_SOURCE		(15<<0)	/* mask - source number */
-#define SND_PCM_AES2_CON_SOURCE_UNSPEC	(0<<0)	/* unspecified */
-#define SND_PCM_AES2_CON_CHANNEL	(15<<4)	/* mask - channel number */
-#define SND_PCM_AES2_CON_CHANNEL_UNSPEC	(0<<4)	/* unspecified */
-#define SND_PCM_AES3_CON_FS		(15<<0)	/* mask - sample frequency */
-#define SND_PCM_AES3_CON_FS_44100	(0<<0)	/* 44.1kHz */
-#define SND_PCM_AES3_CON_FS_48000	(2<<0)	/* 48kHz */
-#define SND_PCM_AES3_CON_FS_32000	(3<<0)	/* 32kHz */
-#define SND_PCM_AES3_CON_CLOCK		(3<<4)	/* mask - clock accuracy */
-#define SND_PCM_AES3_CON_CLOCK_1000PPM	(0<<4)	/* 1000 ppm */
-#define SND_PCM_AES3_CON_CLOCK_50PPM	(1<<4)	/* 50 ppm */
-#define SND_PCM_AES3_CON_CLOCK_VARIABLE	(2<<4)	/* variable pitch */
-
-/*
- * User interface
- */
-
-/*
- * in this loop, dmabuf.count signifies the amount of data that is
- * waiting to be copied to the user's buffer.  it is filled by the dma
- * machine and drained by this loop.
- */
-static ssize_t
-ymf_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf;
-	struct ymf_unit *unit = state->unit;
-	DECLARE_WAITQUEUE(waita, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned int swptr;
-	int cnt;			/* This many to go in this revolution */
-
-	if (dmabuf->mapped)
-		return -ENXIO;
-	if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
-		return ret;
-	ret = 0;
-
-	add_wait_queue(&dmabuf->wait, &waita);
-	set_current_state(TASK_INTERRUPTIBLE);
-	while (count > 0) {
-		spin_lock_irqsave(&unit->reg_lock, flags);
-		if (unit->suspended) {
-			spin_unlock_irqrestore(&unit->reg_lock, flags);
-			schedule();
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (signal_pending(current)) {
-				if (!ret) ret = -EAGAIN;
-				break;
-			}
-			continue;
-		}
-		swptr = dmabuf->swptr;
-		cnt = dmabuf->dmasize - swptr;
-		if (dmabuf->count < cnt)
-			cnt = dmabuf->count;
-		spin_unlock_irqrestore(&unit->reg_lock, flags);
-
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			unsigned long tmo;
-			/* buffer is empty, start the dma machine and wait for data to be
-			   recorded */
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
-			if (!state->rpcm.running) {
-				ymf_capture_trigger(state->unit, &state->rpcm, 1);
-			}
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret) ret = -EAGAIN;
-				break;
-			}
-			/* This isnt strictly right for the 810  but it'll do */
-			tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2);
-			tmo >>= state->format.shift;
-			/* There are two situations when sleep_on_timeout returns, one is when
-			   the interrupt is serviced correctly and the process is waked up by
-			   ISR ON TIME. Another is when timeout is expired, which means that
-			   either interrupt is NOT serviced correctly (pending interrupt) or it
-			   is TOO LATE for the process to be scheduled to run (scheduler latency)
-			   which results in a (potential) buffer overrun. And worse, there is
-			   NOTHING we can do to prevent it. */
-			tmo = schedule_timeout(tmo);
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (tmo == 0 && dmabuf->count == 0) {
-				printk(KERN_ERR "ymfpci%d: recording schedule timeout, "
-				    "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
-				    state->unit->dev_audio,
-				    dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
-				    dmabuf->hwptr, dmabuf->swptr);
-			}
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-			if (signal_pending(current)) {
-				if (!ret) ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-
-		if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
-			if (!ret) ret = -EFAULT;
-			break;
-		}
-
-		swptr = (swptr + cnt) % dmabuf->dmasize;
-
-		spin_lock_irqsave(&unit->reg_lock, flags);
-		if (unit->suspended) {
-			spin_unlock_irqrestore(&unit->reg_lock, flags);
-			continue;
-		}
-
-		dmabuf->swptr = swptr;
-		dmabuf->count -= cnt;
-		// spin_unlock_irqrestore(&unit->reg_lock, flags);
-
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-		// spin_lock_irqsave(&unit->reg_lock, flags);
-		if (!state->rpcm.running) {
-			ymf_capture_trigger(unit, &state->rpcm, 1);
-		}
-		spin_unlock_irqrestore(&unit->reg_lock, flags);
-	}
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&dmabuf->wait, &waita);
-
-	return ret;
-}
-
-static ssize_t
-ymf_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
-	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
-	struct ymf_unit *unit = state->unit;
-	DECLARE_WAITQUEUE(waita, current);
-	ssize_t ret;
-	unsigned long flags;
-	unsigned int swptr;
-	int cnt;			/* This many to go in this revolution */
-	int redzone;
-	int delay;
-
-	YMFDBGW("ymf_write: count %d\n", count);
-
-	if (dmabuf->mapped)
-		return -ENXIO;
-	if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
-		return ret;
-	ret = 0;
-
-	/*
-	 * Alan's cs46xx works without a red zone - marvel of ingenuity.
-	 * We are not so brilliant... Red zone does two things:
-	 *  1. allows for safe start after a pause as we have no way
-	 *     to know what the actual, relentlessly advancing, hwptr is.
-	 *  2. makes computations in ymf_pcm_interrupt simpler.
-	 */
-	redzone = ymf_calc_lend(state->format.rate) << state->format.shift;
-	redzone *= 3;	/* 2 redzone + 1 possible uncertainty reserve. */
-
-	add_wait_queue(&dmabuf->wait, &waita);
-	set_current_state(TASK_INTERRUPTIBLE);
-	while (count > 0) {
-		spin_lock_irqsave(&unit->reg_lock, flags);
-		if (unit->suspended) {
-			spin_unlock_irqrestore(&unit->reg_lock, flags);
-			schedule();
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (signal_pending(current)) {
-				if (!ret) ret = -EAGAIN;
-				break;
-			}
-			continue;
-		}
-		if (dmabuf->count < 0) {
-			printk(KERN_ERR
-			   "ymf_write: count %d, was legal in cs46xx\n",
-			    dmabuf->count);
-			dmabuf->count = 0;
-		}
-		if (dmabuf->count == 0) {
-			swptr = dmabuf->hwptr;
-			if (state->wpcm.running) {
-				/*
-				 * Add uncertainty reserve.
-				 */
-				cnt = ymf_calc_lend(state->format.rate);
-				cnt <<= state->format.shift;
-				if ((swptr += cnt) >= dmabuf->dmasize) {
-					swptr -= dmabuf->dmasize;
-				}
-			}
-			dmabuf->swptr = swptr;
-		} else {
-			/*
-			 * XXX This is not right if dmabuf->count is small -
-			 * about 2*x frame size or less. We cannot count on
-			 * on appending and not causing an artefact.
-			 * Should use a variation of the count==0 case above.
-			 */
-			swptr = dmabuf->swptr;
-		}
-		cnt = dmabuf->dmasize - swptr;
-		if (dmabuf->count + cnt > dmabuf->dmasize - redzone)
-			cnt = (dmabuf->dmasize - redzone) - dmabuf->count;
-		spin_unlock_irqrestore(&unit->reg_lock, flags);
-
-		if (cnt > count)
-			cnt = count;
-		if (cnt <= 0) {
-			YMFDBGW("ymf_write: full, count %d swptr %d\n",
-			   dmabuf->count, dmabuf->swptr);
-			/*
-			 * buffer is full, start the dma machine and
-			 * wait for data to be played
-			 */
-			spin_lock_irqsave(&unit->reg_lock, flags);
-			if (!state->wpcm.running) {
-				ymf_playback_trigger(unit, &state->wpcm, 1);
-			}
-			spin_unlock_irqrestore(&unit->reg_lock, flags);
-			if (file->f_flags & O_NONBLOCK) {
-				if (!ret) ret = -EAGAIN;
-				break;
-			}
-			schedule();
-			set_current_state(TASK_INTERRUPTIBLE);
-			if (signal_pending(current)) {
-				if (!ret) ret = -ERESTARTSYS;
-				break;
-			}
-			continue;
-		}
-		if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
-			if (!ret) ret = -EFAULT;
-			break;
-		}
-
-		if ((swptr += cnt) >= dmabuf->dmasize) {
-			swptr -= dmabuf->dmasize;
-		}
-
-		spin_lock_irqsave(&unit->reg_lock, flags);
-		if (unit->suspended) {
-			spin_unlock_irqrestore(&unit->reg_lock, flags);
-			continue;
-		}
-		dmabuf->swptr = swptr;
-		dmabuf->count += cnt;
-
-		/*
-		 * Start here is a bad idea - may cause startup click
-		 * in /bin/play when dmabuf is not full yet.
-		 * However, some broken applications do not make
-		 * any use of SNDCTL_DSP_SYNC (Doom is the worst).
-		 * One frame is about 5.3ms, Doom write size is 46ms.
-		 */
-		delay = state->format.rate / 20;	/* 50ms */
-		delay <<= state->format.shift;
-		if (dmabuf->count >= delay && !state->wpcm.running) {
-			ymf_playback_trigger(unit, &state->wpcm, 1);
-		}
-
-		spin_unlock_irqrestore(&unit->reg_lock, flags);
-
-		count -= cnt;
-		buffer += cnt;
-		ret += cnt;
-	}
-
-	set_current_state(TASK_RUNNING);
-	remove_wait_queue(&dmabuf->wait, &waita);
-
-	YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count);
-	return ret;
-}
-
-static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait)
-{
-	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	struct ymf_dmabuf *dmabuf;
-	int redzone;
-	unsigned long flags;
-	unsigned int mask = 0;
-
-	if (file->f_mode & FMODE_WRITE)
-		poll_wait(file, &state->wpcm.dmabuf.wait, wait);
-	if (file->f_mode & FMODE_READ)
-		poll_wait(file, &state->rpcm.dmabuf.wait, wait);
-
-	spin_lock_irqsave(&state->unit->reg_lock, flags);
-	if (file->f_mode & FMODE_READ) {
-		dmabuf = &state->rpcm.dmabuf;
-		if (dmabuf->count >= (signed)dmabuf->fragsize)
-			mask |= POLLIN | POLLRDNORM;
-	}
-	if (file->f_mode & FMODE_WRITE) {
-		redzone = ymf_calc_lend(state->format.rate);
-		redzone <<= state->format.shift;
-		redzone *= 3;
-
-		dmabuf = &state->wpcm.dmabuf;
-		if (dmabuf->mapped) {
-			if (dmabuf->count >= (signed)dmabuf->fragsize)
-				mask |= POLLOUT | POLLWRNORM;
-		} else {
-			/*
-			 * Don't select unless a full fragment is available.
-			 * Otherwise artsd does GETOSPACE, sees 0, and loops.
-			 */
-			if (dmabuf->count + redzone + dmabuf->fragsize
-			     <= dmabuf->dmasize)
-				mask |= POLLOUT | POLLWRNORM;
-		}
-	}
-	spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-
-	return mask;
-}
-
-static int ymf_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
-	int ret;
-	unsigned long size;
-
-	if (vma->vm_flags & VM_WRITE) {
-		if ((ret = prog_dmabuf(state, 0)) != 0)
-			return ret;
-	} else if (vma->vm_flags & VM_READ) {
-		if ((ret = prog_dmabuf(state, 1)) != 0)
-			return ret;
-	} else 
-		return -EINVAL;
-
-	if (vma->vm_pgoff != 0)
-		return -EINVAL;
-	size = vma->vm_end - vma->vm_start;
-	if (size > (PAGE_SIZE << dmabuf->buforder))
-		return -EINVAL;
-	if (remap_pfn_range(vma, vma->vm_start,
-			     virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
-			     size, vma->vm_page_prot))
-		return -EAGAIN;
-	dmabuf->mapped = 1;
-
-/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");
-	return 0;
-}
-
-static int ymf_ioctl(struct inode *inode, struct file *file,
-    unsigned int cmd, unsigned long arg)
-{
-	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	struct ymf_dmabuf *dmabuf;
-	unsigned long flags;
-	audio_buf_info abinfo;
-	count_info cinfo;
-	int redzone;
-	int val;
-	void __user *argp = (void __user *)arg;
-	int __user *p = argp;
-
-	switch (cmd) {
-	case OSS_GETVERSION:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
-		return put_user(SOUND_VERSION, p);
-
-	case SNDCTL_DSP_RESET:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
-		if (file->f_mode & FMODE_WRITE) {
-			ymf_wait_dac(state);
-			dmabuf = &state->wpcm.dmabuf;
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
-			dmabuf->ready = 0;
-			dmabuf->swptr = dmabuf->hwptr;
-			dmabuf->count = dmabuf->total_bytes = 0;
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		}
-		if (file->f_mode & FMODE_READ) {
-			ymf_stop_adc(state);
-			dmabuf = &state->rpcm.dmabuf;
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
-			dmabuf->ready = 0;
-			dmabuf->swptr = dmabuf->hwptr;
-			dmabuf->count = dmabuf->total_bytes = 0;
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		}
-		return 0;
-
-	case SNDCTL_DSP_SYNC:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
-		if (file->f_mode & FMODE_WRITE) {
-			dmabuf = &state->wpcm.dmabuf;
-			if (file->f_flags & O_NONBLOCK) {
-				spin_lock_irqsave(&state->unit->reg_lock, flags);
-				if (dmabuf->count != 0 && !state->wpcm.running) {
-					ymf_start_dac(state);
-				}
-				spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-			} else {
-				ymf_wait_dac(state);
-			}
-		}
-		/* XXX What does this do for reading? dmabuf->count=0; ? */
-		return 0;
-
-	case SNDCTL_DSP_SPEED: /* set smaple rate */
-		if (get_user(val, p))
-			return -EFAULT;
-		YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
-		if (val >= 8000 && val <= 48000) {
-			if (file->f_mode & FMODE_WRITE) {
-				ymf_wait_dac(state);
-				dmabuf = &state->wpcm.dmabuf;
-				spin_lock_irqsave(&state->unit->reg_lock, flags);
-				dmabuf->ready = 0;
-				state->format.rate = val;
-				ymf_pcm_update_shift(&state->format);
-				spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-			}
-			if (file->f_mode & FMODE_READ) {
-				ymf_stop_adc(state);
-				dmabuf = &state->rpcm.dmabuf;
-				spin_lock_irqsave(&state->unit->reg_lock, flags);
-				dmabuf->ready = 0;
-				state->format.rate = val;
-				ymf_pcm_update_shift(&state->format);
-				spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-			}
-		}
-		return put_user(state->format.rate, p);
-
-	/*
-	 * OSS manual does not mention SNDCTL_DSP_STEREO at all.
-	 * All channels are mono and if you want stereo, you
-	 * play into two channels with SNDCTL_DSP_CHANNELS.
-	 * However, mpg123 calls it. I wonder, why Michael Hipp used it.
-	 */
-	case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
-		if (get_user(val, p))
-			return -EFAULT;
-		YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
-		if (file->f_mode & FMODE_WRITE) {
-			ymf_wait_dac(state); 
-			dmabuf = &state->wpcm.dmabuf;
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
-			dmabuf->ready = 0;
-			state->format.voices = val ? 2 : 1;
-			ymf_pcm_update_shift(&state->format);
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		}
-		if (file->f_mode & FMODE_READ) {
-			ymf_stop_adc(state);
-			dmabuf = &state->rpcm.dmabuf;
-			spin_lock_irqsave(&state->unit->reg_lock, flags);
-			dmabuf->ready = 0;
-			state->format.voices = val ? 2 : 1;
-			ymf_pcm_update_shift(&state->format);
-			spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		}
-		return 0;
-
-	case SNDCTL_DSP_GETBLKSIZE:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
-		if (file->f_mode & FMODE_WRITE) {
-			if ((val = prog_dmabuf(state, 0)))
-				return val;
-			val = state->wpcm.dmabuf.fragsize;
-			YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
-			return put_user(val, p);
-		}
-		if (file->f_mode & FMODE_READ) {
-			if ((val = prog_dmabuf(state, 1)))
-				return val;
-			val = state->rpcm.dmabuf.fragsize;
-			YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
-			return put_user(val, p);
-		}
-		return -EINVAL;
-
-	case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
-		return put_user(AFMT_S16_LE|AFMT_U8, p);
-
-	case SNDCTL_DSP_SETFMT: /* Select sample format */
-		if (get_user(val, p))
-			return -EFAULT;
-		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
-		if (val == AFMT_S16_LE || val == AFMT_U8) {
-			if (file->f_mode & FMODE_WRITE) {
-				ymf_wait_dac(state);
-				dmabuf = &state->wpcm.dmabuf;
-				spin_lock_irqsave(&state->unit->reg_lock, flags);
-				dmabuf->ready = 0;
-				state->format.format = val;
-				ymf_pcm_update_shift(&state->format);
-				spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-			}
-			if (file->f_mode & FMODE_READ) {
-				ymf_stop_adc(state);
-				dmabuf = &state->rpcm.dmabuf;
-				spin_lock_irqsave(&state->unit->reg_lock, flags);
-				dmabuf->ready = 0;
-				state->format.format = val;
-				ymf_pcm_update_shift(&state->format);
-				spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-			}
-		}
-		return put_user(state->format.format, p);
-
-	case SNDCTL_DSP_CHANNELS:
-		if (get_user(val, p))
-			return -EFAULT;
-		YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
-		if (val != 0) {
-			if (file->f_mode & FMODE_WRITE) {
-				ymf_wait_dac(state);
-				if (val == 1 || val == 2) {
-					spin_lock_irqsave(&state->unit->reg_lock, flags);
-					dmabuf = &state->wpcm.dmabuf;
-					dmabuf->ready = 0;
-					state->format.voices = val;
-					ymf_pcm_update_shift(&state->format);
-					spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-				}
-			}
-			if (file->f_mode & FMODE_READ) {
-				ymf_stop_adc(state);
-				if (val == 1 || val == 2) {
-					spin_lock_irqsave(&state->unit->reg_lock, flags);
-					dmabuf = &state->rpcm.dmabuf;
-					dmabuf->ready = 0;
-					state->format.voices = val;
-					ymf_pcm_update_shift(&state->format);
-					spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-				}
-			}
-		}
-		return put_user(state->format.voices, p);
-
-	case SNDCTL_DSP_POST:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
-		/*
-		 * Quoting OSS PG:
-		 *    The ioctl SNDCTL_DSP_POST is a lightweight version of
-		 *    SNDCTL_DSP_SYNC. It just tells to the driver that there
-		 *    is likely to be a pause in the output. This makes it
-		 *    possible for the device to handle the pause more
-		 *    intelligently. This ioctl doesn't block the application.
-		 *
-		 * The paragraph above is a clumsy way to say "flush ioctl".
-		 * This ioctl is used by mpg123.
-		 */
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
-		if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) {
-			ymf_start_dac(state);
-		}
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		return 0;
-
-	case SNDCTL_DSP_SETFRAGMENT:
-		if (get_user(val, p))
-			return -EFAULT;
-		YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
-		    cmd,
-		    (val >> 16) & 0xFFFF, val & 0xFFFF,
-		    (val >> 16) & 0xFFFF, val & 0xFFFF);
-		dmabuf = &state->wpcm.dmabuf;
-		dmabuf->ossfragshift = val & 0xffff;
-		dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
-		if (dmabuf->ossfragshift < 4)
-			dmabuf->ossfragshift = 4;
-		if (dmabuf->ossfragshift > 15)
-			dmabuf->ossfragshift = 15;
-		return 0;
-
-	case SNDCTL_DSP_GETOSPACE:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		dmabuf = &state->wpcm.dmabuf;
-		if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
-			return val;
-		redzone = ymf_calc_lend(state->format.rate);
-		redzone <<= state->format.shift;
-		redzone *= 3;
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
-		abinfo.fragsize = dmabuf->fragsize;
-		abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
-		abinfo.fragstotal = dmabuf->numfrag;
-		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETISPACE:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		dmabuf = &state->rpcm.dmabuf;
-		if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
-			return val;
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
-		abinfo.fragsize = dmabuf->fragsize;
-		abinfo.bytes = dmabuf->count;
-		abinfo.fragstotal = dmabuf->numfrag;
-		abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_NONBLOCK:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
-		file->f_flags |= O_NONBLOCK;
-		return 0;
-
-	case SNDCTL_DSP_GETCAPS:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
-		/* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
-			    p); */
-		return put_user(0, p);
-
-	case SNDCTL_DSP_GETIPTR:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
-		if (!(file->f_mode & FMODE_READ))
-			return -EINVAL;
-		dmabuf = &state->rpcm.dmabuf;
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
-		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
-		cinfo.ptr = dmabuf->hwptr;
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
-		    cinfo.ptr, cinfo.bytes);
-		return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_GETOPTR:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
-		if (!(file->f_mode & FMODE_WRITE))
-			return -EINVAL;
-		dmabuf = &state->wpcm.dmabuf;
-		spin_lock_irqsave(&state->unit->reg_lock, flags);
-		cinfo.bytes = dmabuf->total_bytes;
-		cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
-		cinfo.ptr = dmabuf->hwptr;
-		spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-		YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
-		    cinfo.ptr, cinfo.bytes);
-		return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
-	case SNDCTL_DSP_SETDUPLEX:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
-		return 0;		/* Always duplex */
-
-	case SOUND_PCM_READ_RATE:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
-		return put_user(state->format.rate, p);
-
-	case SOUND_PCM_READ_CHANNELS:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
-		return put_user(state->format.voices, p);
-
-	case SOUND_PCM_READ_BITS:
-		YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
-		return put_user(AFMT_S16_LE, p);
-
-	case SNDCTL_DSP_MAPINBUF:
-	case SNDCTL_DSP_MAPOUTBUF:
-	case SNDCTL_DSP_SETSYNCRO:
-	case SOUND_PCM_WRITE_FILTER:
-	case SOUND_PCM_READ_FILTER:
-		YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd);
-		return -ENOTTY;
-
-	default:
-		/*
-		 * Some programs mix up audio devices and ioctls
-		 * or perhaps they expect "universal" ioctls,
-		 * for instance we get SNDCTL_TMR_CONTINUE here.
-		 * (mpg123 -g 100 ends here too - to be fixed.)
-		 */
-		YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
-		break;
-	}
-	return -ENOTTY;
-}
-
-/*
- * open(2)
- * We use upper part of the minor to distinguish between soundcards.
- * Channels are opened with a clone open.
- */
-static int ymf_open(struct inode *inode, struct file *file)
-{
-	struct list_head *list;
-	ymfpci_t *unit = NULL;
-	int minor;
-	struct ymf_state *state;
-	int err;
-
-	minor = iminor(inode);
-	if ((minor & 0x0F) == 3) {	/* /dev/dspN */
-		;
-	} else {
-		return -ENXIO;
-	}
-
-	unit = NULL;	/* gcc warns */
-	spin_lock(&ymf_devs_lock);
-	list_for_each(list, &ymf_devs) {
-		unit = list_entry(list, ymfpci_t, ymf_devs);
-		if (((unit->dev_audio ^ minor) & ~0x0F) == 0)
-			break;
-	}
-	spin_unlock(&ymf_devs_lock);
-	if (unit == NULL)
-		return -ENODEV;
-
-	mutex_lock(&unit->open_mutex);
-
-	if ((state = ymf_state_alloc(unit)) == NULL) {
-		mutex_unlock(&unit->open_mutex);
-		return -ENOMEM;
-	}
-	list_add_tail(&state->chain, &unit->states);
-
-	file->private_data = state;
-
-	/*
-	 * ymf_read and ymf_write that we borrowed from cs46xx
-	 * allocate buffers with prog_dmabuf(). We call prog_dmabuf
-	 * here so that in case of DMA memory exhaustion open
-	 * fails rather than write.
-	 *
-	 * XXX prog_dmabuf allocates voice. Should allocate explicitly, above.
-	 */
-	if (file->f_mode & FMODE_WRITE) {
-		if (!state->wpcm.dmabuf.ready) {
-			if ((err = prog_dmabuf(state, 0)) != 0) {
-				goto out_nodma;
-			}
-		}
-	}
-	if (file->f_mode & FMODE_READ) {
-		if (!state->rpcm.dmabuf.ready) {
-			if ((err = prog_dmabuf(state, 1)) != 0) {
-				goto out_nodma;
-			}
-		}
-	}
-
-#if 0 /* test if interrupts work */
-	ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe);	/* ~ 680ms */
-	ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
-	    (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
-#endif
-	mutex_unlock(&unit->open_mutex);
-
-	return nonseekable_open(inode, file);
-
-out_nodma:
-	/*
-	 * XXX Broken custom: "goto out_xxx" in other place is
-	 * a nestable exception, but here it is not nestable due to semaphore.
-	 * XXX Doubtful technique of self-describing objects....
-	 */
-	dealloc_dmabuf(unit, &state->wpcm.dmabuf);
-	dealloc_dmabuf(unit, &state->rpcm.dmabuf);
-	ymf_pcm_free_substream(&state->wpcm);
-	ymf_pcm_free_substream(&state->rpcm);
-
-	list_del(&state->chain);
-	kfree(state);
-
-	mutex_unlock(&unit->open_mutex);
-	return err;
-}
-
-static int ymf_release(struct inode *inode, struct file *file)
-{
-	struct ymf_state *state = (struct ymf_state *)file->private_data;
-	ymfpci_t *unit = state->unit;
-
-#if 0 /* test if interrupts work */
-	ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
-#endif
-
-	mutex_lock(&unit->open_mutex);
-
-	/*
-	 * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
-	 * Deallocate when unloading the driver and we can wait.
-	 */
-	ymf_wait_dac(state);
-	ymf_stop_adc(state);		/* fortunately, it's immediate */
-	dealloc_dmabuf(unit, &state->wpcm.dmabuf);
-	dealloc_dmabuf(unit, &state->rpcm.dmabuf);
-	ymf_pcm_free_substream(&state->wpcm);
-	ymf_pcm_free_substream(&state->rpcm);
-
-	list_del(&state->chain);
-	file->private_data = NULL;	/* Can you tell I programmed Solaris */
-	kfree(state);
-
-	mutex_unlock(&unit->open_mutex);
-
-	return 0;
-}
-
-/*
- * Mixer operations are based on cs46xx.
- */
-static int ymf_open_mixdev(struct inode *inode, struct file *file)
-{
-	int minor = iminor(inode);
-	struct list_head *list;
-	ymfpci_t *unit;
-	int i;
-
-	spin_lock(&ymf_devs_lock);
-	list_for_each(list, &ymf_devs) {
-		unit = list_entry(list, ymfpci_t, ymf_devs);
-		for (i = 0; i < NR_AC97; i++) {
-			if (unit->ac97_codec[i] != NULL &&
-			    unit->ac97_codec[i]->dev_mixer == minor) {
-				spin_unlock(&ymf_devs_lock);
-				goto match;
-			}
-		}
-	}
-	spin_unlock(&ymf_devs_lock);
-	return -ENODEV;
-
- match:
-	file->private_data = unit->ac97_codec[i];
-
-	return nonseekable_open(inode, file);
-}
-
-static int ymf_ioctl_mixdev(struct inode *inode, struct file *file,
-    unsigned int cmd, unsigned long arg)
-{
-	struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
-	return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static int ymf_release_mixdev(struct inode *inode, struct file *file)
-{
-	return 0;
-}
-
-static /*const*/ struct file_operations ymf_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= ymf_read,
-	.write		= ymf_write,
-	.poll		= ymf_poll,
-	.ioctl		= ymf_ioctl,
-	.mmap		= ymf_mmap,
-	.open		= ymf_open,
-	.release	= ymf_release,
-};
-
-static /*const*/ struct file_operations ymf_mixer_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.ioctl		= ymf_ioctl_mixdev,
-	.open		= ymf_open_mixdev,
-	.release	= ymf_release_mixdev,
-};
-
-/*
- */
-
-static int ymf_suspend(struct pci_dev *pcidev, pm_message_t unused)
-{
-	struct ymf_unit *unit = pci_get_drvdata(pcidev);
-	unsigned long flags;
-	struct ymf_dmabuf *dmabuf;
-	struct list_head *p;
-	struct ymf_state *state;
-	struct ac97_codec *codec;
-	int i;
-
-	spin_lock_irqsave(&unit->reg_lock, flags);
-
-	unit->suspended = 1;
-
-	for (i = 0; i < NR_AC97; i++) {
-		if ((codec = unit->ac97_codec[i]) != NULL)
-			ac97_save_state(codec);
-	}
-
-	list_for_each(p, &unit->states) {
-		state = list_entry(p, struct ymf_state, chain);
-
-		dmabuf = &state->wpcm.dmabuf;
-		dmabuf->hwptr = dmabuf->swptr = 0;
-		dmabuf->total_bytes = 0;
-		dmabuf->count = 0;
-
-		dmabuf = &state->rpcm.dmabuf;
-		dmabuf->hwptr = dmabuf->swptr = 0;
-		dmabuf->total_bytes = 0;
-		dmabuf->count = 0;
-	}
-
-	ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0);
-	ymfpci_disable_dsp(unit);
-
-	spin_unlock_irqrestore(&unit->reg_lock, flags);
-	
-	return 0;
-}
-
-static int ymf_resume(struct pci_dev *pcidev)
-{
-	struct ymf_unit *unit = pci_get_drvdata(pcidev);
-	unsigned long flags;
-	struct list_head *p;
-	struct ymf_state *state;
-	struct ac97_codec *codec;
-	int i;
-
-	ymfpci_aclink_reset(unit->pci);
-	ymfpci_codec_ready(unit, 0, 1);		/* prints diag if not ready. */
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-	/* XXX At this time the legacy registers are probably deprogrammed. */
-#endif
-
-	ymfpci_download_image(unit);
-
-	ymf_memload(unit);
-
-	spin_lock_irqsave(&unit->reg_lock, flags);
-
-	if (unit->start_count) {
-		ymfpci_writel(unit, YDSXGR_MODE, 3);
-		unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
-	}
-
-	for (i = 0; i < NR_AC97; i++) {
-		if ((codec = unit->ac97_codec[i]) != NULL)
-			ac97_restore_state(codec);
-	}
-
-	unit->suspended = 0;
-	list_for_each(p, &unit->states) {
-		state = list_entry(p, struct ymf_state, chain);
-		wake_up(&state->wpcm.dmabuf.wait);
-		wake_up(&state->rpcm.dmabuf.wait);
-	}
-
-	spin_unlock_irqrestore(&unit->reg_lock, flags);
-	return 0;
-}
-
-/*
- *  initialization routines
- */
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-
-static int ymfpci_setup_legacy(ymfpci_t *unit, struct pci_dev *pcidev)
-{
-	int v;
-	int mpuio = -1, oplio = -1;
-
-	switch (unit->iomidi) {
-	case 0x330:
-		mpuio = 0;
-		break;
-	case 0x300:
-		mpuio = 1;
-		break;
-	case 0x332:
-		mpuio = 2;
-		break;
-	case 0x334:
-		mpuio = 3;
-		break;
-	default: ;
-	}
-
-	switch (unit->iosynth) {
-	case 0x388:
-		oplio = 0;
-		break;
-	case 0x398:
-		oplio = 1;
-		break;
-	case 0x3a0:
-		oplio = 2;
-		break;
-	case 0x3a8:
-		oplio = 3;
-		break;
-	default: ;
-	}
-
-	if (mpuio >= 0 || oplio >= 0) {
-		/* 0x0020: 1 - 10 bits of I/O address decoded, 0 - 16 bits. */
-		v = 0x001e;
-		pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
-
-		switch (pcidev->device) {
-		case PCI_DEVICE_ID_YAMAHA_724:
-		case PCI_DEVICE_ID_YAMAHA_740:
-		case PCI_DEVICE_ID_YAMAHA_724F:
-		case PCI_DEVICE_ID_YAMAHA_740C:
-			v = 0x8800;
-			if (mpuio >= 0) { v |= mpuio<<4; }
-			if (oplio >= 0) { v |= oplio; }
-			pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
-			break;
-
-		case PCI_DEVICE_ID_YAMAHA_744:
-		case PCI_DEVICE_ID_YAMAHA_754:
-			v = 0x8800;
-			pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
-			if (oplio >= 0) {
-				pci_write_config_word(pcidev, PCIR_OPLADR, unit->iosynth);
-			}
-			if (mpuio >= 0) {
-				pci_write_config_word(pcidev, PCIR_MPUADR, unit->iomidi);
-			}
-			break;
-
-		default:
-			printk(KERN_ERR "ymfpci: Unknown device ID: 0x%x\n",
-			    pcidev->device);
-			return -EINVAL;
-		}
-	}
-
-	return 0;
-}
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
-static void ymfpci_aclink_reset(struct pci_dev * pci)
-{
-	u8 cmd;
-
-	/*
-	 * In the 744, 754 only 0x01 exists, 0x02 is undefined.
-	 * It does not seem to hurt to trip both regardless of revision.
-	 */
-	pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
-	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
-	pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-
-	pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
-	pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
-}
-
-static void ymfpci_enable_dsp(ymfpci_t *codec)
-{
-	ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000001);
-}
-
-static void ymfpci_disable_dsp(ymfpci_t *codec)
-{
-	u32 val;
-	int timeout = 1000;
-
-	val = ymfpci_readl(codec, YDSXGR_CONFIG);
-	if (val)
-		ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000);
-	while (timeout-- > 0) {
-		val = ymfpci_readl(codec, YDSXGR_STATUS);
-		if ((val & 0x00000002) == 0)
-			break;
-	}
-}
-
-#include "ymfpci_image.h"
-
-static void ymfpci_download_image(ymfpci_t *codec)
-{
-	int i, ver_1e;
-	u16 ctrl;
-
-	ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
-	ymfpci_disable_dsp(codec);
-	ymfpci_writel(codec, YDSXGR_MODE, 0x00010000);
-	ymfpci_writel(codec, YDSXGR_MODE, 0x00000000);
-	ymfpci_writel(codec, YDSXGR_MAPOFREC, 0x00000000);
-	ymfpci_writel(codec, YDSXGR_MAPOFEFFECT, 0x00000000);
-	ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0x00000000);
-	ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0x00000000);
-	ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0x00000000);
-	ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
-	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
-
-	/* setup DSP instruction code */
-	for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
-		ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
-
-	switch (codec->pci->device) {
-	case PCI_DEVICE_ID_YAMAHA_724F:
-	case PCI_DEVICE_ID_YAMAHA_740C:
-	case PCI_DEVICE_ID_YAMAHA_744:
-	case PCI_DEVICE_ID_YAMAHA_754:
-		ver_1e = 1;
-		break;
-	default:
-		ver_1e = 0;
-	}
-
-	if (ver_1e) {
-		/* setup control instruction code */
-		for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
-			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]);
-	} else {
-		for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
-			ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]);
-	}
-
-	ymfpci_enable_dsp(codec);
-
-	/* 0.02s sounds not too bad, we may do schedule_timeout() later. */
-	mdelay(20); /* seems we need some delay after downloading image.. */
-}
-
-static int ymfpci_memalloc(ymfpci_t *codec)
-{
-	unsigned int playback_ctrl_size;
-	unsigned int bank_size_playback;
-	unsigned int bank_size_capture;
-	unsigned int bank_size_effect;
-	unsigned int size;
-	unsigned int off;
-	char *ptr;
-	dma_addr_t pba;
-	int voice, bank;
-
-	playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
-	bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
-	bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
-	bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
-	codec->work_size = YDSXG_DEFAULT_WORK_SIZE;
-
-	size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
-	    ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
-	    ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
-	    ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
-	    codec->work_size;
-
-	ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba);
-	if (ptr == NULL)
-		return -ENOMEM;
-	codec->dma_area_va = ptr;
-	codec->dma_area_ba = pba;
-	codec->dma_area_size = size + 0xff;
-
-	off = (unsigned long)ptr & 0xff;
-	if (off) {
-		ptr += 0x100 - off;
-		pba += 0x100 - off;
-	}
-
-	/*
-	 * Hardware requires only ptr[playback_ctrl_size] zeroed,
-	 * but in our judgement it is a wrong kind of savings, so clear it all.
-	 */
-	memset(ptr, 0, size);
-
-	codec->ctrl_playback = (u32 *)ptr;
-	codec->ctrl_playback_ba = pba;
-	codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
-	ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
-	pba += (playback_ctrl_size + 0x00ff) & ~0x00ff;
-
-	off = 0;
-	for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
-		codec->voices[voice].number = voice;
-		codec->voices[voice].bank =
-		    (ymfpci_playback_bank_t *) (ptr + off);
-		codec->voices[voice].bank_ba = pba + off;
-		off += 2 * bank_size_playback;		/* 2 banks */
-	}
-	off = (off + 0xff) & ~0xff;
-	ptr += off;
-	pba += off;
-
-	off = 0;
-	codec->bank_base_capture = pba;
-	for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
-		for (bank = 0; bank < 2; bank++) {
-			codec->bank_capture[voice][bank] =
-			    (ymfpci_capture_bank_t *) (ptr + off);
-			off += bank_size_capture;
-		}
-	off = (off + 0xff) & ~0xff;
-	ptr += off;
-	pba += off;
-
-	off = 0;
-	codec->bank_base_effect = pba;
-	for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
-		for (bank = 0; bank < 2; bank++) {
-			codec->bank_effect[voice][bank] =
-			    (ymfpci_effect_bank_t *) (ptr + off);
-			off += bank_size_effect;
-		}
-	off = (off + 0xff) & ~0xff;
-	ptr += off;
-	pba += off;
-
-	codec->work_base = pba;
-
-	return 0;
-}
-
-static void ymfpci_memfree(ymfpci_t *codec)
-{
-	ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0);
-	ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0);
-	ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);
-	ymfpci_writel(codec, YDSXGR_WORKBASE, 0);
-	ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);
-	pci_free_consistent(codec->pci,
-	    codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba);
-}
-
-static void ymf_memload(ymfpci_t *unit)
-{
-
-	ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba);
-	ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture);
-	ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect);
-	ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base);
-	ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
-
-	/* S/PDIF output initialization */
-	ymfpci_writew(unit, YDSXGR_SPDIFOUTCTRL, 0);
-	ymfpci_writew(unit, YDSXGR_SPDIFOUTSTATUS,
-		SND_PCM_AES0_CON_EMPHASIS_NONE |
-		(SND_PCM_AES1_CON_ORIGINAL << 8) |
-		(SND_PCM_AES1_CON_PCM_CODER << 8));
-
-	/* S/PDIF input initialization */
-	ymfpci_writew(unit, YDSXGR_SPDIFINCTRL, 0);
-
-	/* move this volume setup to mixer */
-	ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
-	ymfpci_writel(unit, YDSXGR_BUF441OUTVOL, 0);
-	ymfpci_writel(unit, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
-	ymfpci_writel(unit, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
-}
-
-static int ymf_ac97_init(ymfpci_t *unit, int num_ac97)
-{
-	struct ac97_codec *codec;
-	u16 eid;
-
-	if ((codec = ac97_alloc_codec()) == NULL)
-		return -ENOMEM;
-
-	/* initialize some basic codec information, other fields will be filled
-	   in ac97_probe_codec */
-	codec->private_data = unit;
-	codec->id = num_ac97;
-
-	codec->codec_read = ymfpci_codec_read;
-	codec->codec_write = ymfpci_codec_write;
-
-	if (ac97_probe_codec(codec) == 0) {
-		printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
-		goto out_kfree;
-	}
-
-	eid = ymfpci_codec_read(codec, AC97_EXTENDED_ID);
-	if (eid==0xFFFF) {
-		printk(KERN_WARNING "ymfpci: no codec attached ?\n");
-		goto out_kfree;
-	}
-
-	unit->ac97_features = eid;
-
-	if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) {
-		printk(KERN_ERR "ymfpci: couldn't register mixer!\n");
-		goto out_kfree;
-	}
-
-	unit->ac97_codec[num_ac97] = codec;
-
-	return 0;
- out_kfree:
-	ac97_release_codec(codec);
-	return -ENODEV;
-}
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-# ifdef MODULE
-static int mpu_io;
-static int synth_io;
-module_param(mpu_io, int, 0);
-module_param(synth_io, int, 0);
-# else
-static int mpu_io     = 0x330;
-static int synth_io   = 0x388;
-# endif
-static int assigned;
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
-static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
-{
-	u16 ctrl;
-	unsigned long base;
-	ymfpci_t *codec;
-
-	int err;
-
-	if ((err = pci_enable_device(pcidev)) != 0) {
-		printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
-		return err;
-	}
-	base = pci_resource_start(pcidev, 0);
-
-	if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
-		printk(KERN_ERR "ymfpci: no core\n");
-		return -ENOMEM;
-	}
-	memset(codec, 0, sizeof(*codec));
-
-	spin_lock_init(&codec->reg_lock);
-	spin_lock_init(&codec->voice_lock);
-	spin_lock_init(&codec->ac97_lock);
-	mutex_init(&codec->open_mutex);
-	INIT_LIST_HEAD(&codec->states);
-	codec->pci = pcidev;
-
-	pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
-
-	if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
-		printk(KERN_ERR "ymfpci: unable to request mem region\n");
-		goto out_free;
-	}
-
-	if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
-		printk(KERN_ERR "ymfpci: unable to map registers\n");
-		goto out_release_region;
-	}
-
-	pci_set_master(pcidev);
-
-	printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
-	    (char *)ent->driver_data, base, pcidev->irq);
-
-	ymfpci_aclink_reset(pcidev);
-	if (ymfpci_codec_ready(codec, 0, 1) < 0)
-		goto out_unmap;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-	if (assigned == 0) {
-		codec->iomidi = mpu_io;
-		codec->iosynth = synth_io;
-		if (ymfpci_setup_legacy(codec, pcidev) < 0)
-			goto out_unmap;
-		assigned = 1;
-	}
-#endif
-
-	ymfpci_download_image(codec);
-
-	if (ymfpci_memalloc(codec) < 0)
-		goto out_disable_dsp;
-	ymf_memload(codec);
-
-	if (request_irq(pcidev->irq, ymf_interrupt, IRQF_SHARED, "ymfpci", codec) != 0) {
-		printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
-		    pcidev->irq);
-		goto out_memfree;
-	}
-
-	/* register /dev/dsp */
-	if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
-		printk(KERN_ERR "ymfpci: unable to register dsp\n");
-		goto out_free_irq;
-	}
-
-	/*
-	 * Poke just the primary for the moment.
-	 */
-	if ((err = ymf_ac97_init(codec, 0)) != 0)
-		goto out_unregister_sound_dsp;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-	codec->opl3_data.name = "ymfpci";
-	codec->mpu_data.name  = "ymfpci";
-
-	codec->opl3_data.io_base = codec->iosynth;
-	codec->opl3_data.irq     = -1;
-
-	codec->mpu_data.io_base  = codec->iomidi;
-	codec->mpu_data.irq      = -1;	/* May be different from our PCI IRQ. */
-
-	if (codec->iomidi) {
-		if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
-			codec->iomidi = 0;	/* XXX kludge */
-		}
-	}
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
-	/* put it into driver list */
-	spin_lock(&ymf_devs_lock);
-	list_add_tail(&codec->ymf_devs, &ymf_devs);
-	spin_unlock(&ymf_devs_lock);
-	pci_set_drvdata(pcidev, codec);
-
-	return 0;
-
- out_unregister_sound_dsp:
-	unregister_sound_dsp(codec->dev_audio);
- out_free_irq:
-	free_irq(pcidev->irq, codec);
- out_memfree:
-	ymfpci_memfree(codec);
- out_disable_dsp:
-	ymfpci_disable_dsp(codec);
-	ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
-	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
-	ymfpci_writel(codec, YDSXGR_STATUS, ~0);
- out_unmap:
-	iounmap(codec->reg_area_virt);
- out_release_region:
-	release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
- out_free:
-	if (codec->ac97_codec[0])
-		ac97_release_codec(codec->ac97_codec[0]);
-	return -ENODEV;
-}
-
-static void __devexit ymf_remove_one(struct pci_dev *pcidev)
-{
-	__u16 ctrl;
-	ymfpci_t *codec = pci_get_drvdata(pcidev);
-
-	/* remove from list of devices */
-	spin_lock(&ymf_devs_lock);
-	list_del(&codec->ymf_devs);
-	spin_unlock(&ymf_devs_lock);
-
-	unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer);
-	ac97_release_codec(codec->ac97_codec[0]);
-	unregister_sound_dsp(codec->dev_audio);
-	free_irq(pcidev->irq, codec);
-	ymfpci_memfree(codec);
-	ymfpci_writel(codec, YDSXGR_STATUS, ~0);
-	ymfpci_disable_dsp(codec);
-	ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
-	ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
-	iounmap(codec->reg_area_virt);
-	release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-	if (codec->iomidi) {
-		unload_uart401(&codec->mpu_data);
-	}
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-}
-
-MODULE_AUTHOR("Jaroslav Kysela");
-MODULE_DESCRIPTION("Yamaha YMF7xx PCI Audio");
-MODULE_LICENSE("GPL");
-
-static struct pci_driver ymfpci_driver = {
-	.name		= "ymfpci",
-	.id_table	= ymf_id_tbl,
-	.probe		= ymf_probe_one,
-	.remove		= __devexit_p(ymf_remove_one),
-	.suspend	= ymf_suspend,
-	.resume		= ymf_resume
-};
-
-static int __init ymf_init_module(void)
-{
-	return pci_register_driver(&ymfpci_driver);
-}
-
-static void __exit ymf_cleanup_module (void)
-{
-	pci_unregister_driver(&ymfpci_driver);
-}
-
-module_init(ymf_init_module);
-module_exit(ymf_cleanup_module);
diff --git a/sound/oss/ymfpci.h b/sound/oss/ymfpci.h
deleted file mode 100644
index ac1785f..0000000
--- a/sound/oss/ymfpci.h
+++ /dev/null
@@ -1,361 +0,0 @@
-#ifndef __YMFPCI_H
-#define __YMFPCI_H
-
-/*
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- *  Definitions for Yahama YMF724/740/744/754 chips
- *
- *
- *   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/mutex.h>
-
-/*
- *  Direct registers
- */
-
-/* #define YMFREG(codec, reg)		(codec->port + YDSXGR_##reg) */
-
-#define	YDSXGR_INTFLAG			0x0004
-#define	YDSXGR_ACTIVITY			0x0006
-#define	YDSXGR_GLOBALCTRL		0x0008
-#define	YDSXGR_ZVCTRL			0x000A
-#define	YDSXGR_TIMERCTRL		0x0010
-#define	YDSXGR_TIMERCTRL_TEN		 0x0001
-#define	YDSXGR_TIMERCTRL_TIEN		 0x0002
-#define	YDSXGR_TIMERCOUNT		0x0012
-#define	YDSXGR_SPDIFOUTCTRL		0x0018
-#define	YDSXGR_SPDIFOUTSTATUS		0x001C
-#define	YDSXGR_EEPROMCTRL		0x0020
-#define	YDSXGR_SPDIFINCTRL		0x0034
-#define	YDSXGR_SPDIFINSTATUS		0x0038
-#define	YDSXGR_DSPPROGRAMDL		0x0048
-#define	YDSXGR_DLCNTRL			0x004C
-#define	YDSXGR_GPIOININTFLAG		0x0050
-#define	YDSXGR_GPIOININTENABLE		0x0052
-#define	YDSXGR_GPIOINSTATUS		0x0054
-#define	YDSXGR_GPIOOUTCTRL		0x0056
-#define	YDSXGR_GPIOFUNCENABLE		0x0058
-#define	YDSXGR_GPIOTYPECONFIG		0x005A
-#define	YDSXGR_AC97CMDDATA		0x0060
-#define	YDSXGR_AC97CMDADR		0x0062
-#define	YDSXGR_PRISTATUSDATA		0x0064
-#define	YDSXGR_PRISTATUSADR		0x0066
-#define	YDSXGR_SECSTATUSDATA		0x0068
-#define	YDSXGR_SECSTATUSADR		0x006A
-#define	YDSXGR_SECCONFIG		0x0070
-#define	YDSXGR_LEGACYOUTVOL		0x0080
-#define	YDSXGR_LEGACYOUTVOLL		0x0080
-#define	YDSXGR_LEGACYOUTVOLR		0x0082
-#define	YDSXGR_NATIVEDACOUTVOL		0x0084
-#define	YDSXGR_NATIVEDACOUTVOLL		0x0084
-#define	YDSXGR_NATIVEDACOUTVOLR		0x0086
-#define	YDSXGR_SPDIFOUTVOL		0x0088
-#define	YDSXGR_SPDIFOUTVOLL		0x0088
-#define	YDSXGR_SPDIFOUTVOLR		0x008A
-#define	YDSXGR_AC3OUTVOL		0x008C
-#define	YDSXGR_AC3OUTVOLL		0x008C
-#define	YDSXGR_AC3OUTVOLR		0x008E
-#define	YDSXGR_PRIADCOUTVOL		0x0090
-#define	YDSXGR_PRIADCOUTVOLL		0x0090
-#define	YDSXGR_PRIADCOUTVOLR		0x0092
-#define	YDSXGR_LEGACYLOOPVOL		0x0094
-#define	YDSXGR_LEGACYLOOPVOLL		0x0094
-#define	YDSXGR_LEGACYLOOPVOLR		0x0096
-#define	YDSXGR_NATIVEDACLOOPVOL		0x0098
-#define	YDSXGR_NATIVEDACLOOPVOLL	0x0098
-#define	YDSXGR_NATIVEDACLOOPVOLR	0x009A
-#define	YDSXGR_SPDIFLOOPVOL		0x009C
-#define	YDSXGR_SPDIFLOOPVOLL		0x009E
-#define	YDSXGR_SPDIFLOOPVOLR		0x009E
-#define	YDSXGR_AC3LOOPVOL		0x00A0
-#define	YDSXGR_AC3LOOPVOLL		0x00A0
-#define	YDSXGR_AC3LOOPVOLR		0x00A2
-#define	YDSXGR_PRIADCLOOPVOL		0x00A4
-#define	YDSXGR_PRIADCLOOPVOLL		0x00A4
-#define	YDSXGR_PRIADCLOOPVOLR		0x00A6
-#define	YDSXGR_NATIVEADCINVOL		0x00A8
-#define	YDSXGR_NATIVEADCINVOLL		0x00A8
-#define	YDSXGR_NATIVEADCINVOLR		0x00AA
-#define	YDSXGR_NATIVEDACINVOL		0x00AC
-#define	YDSXGR_NATIVEDACINVOLL		0x00AC
-#define	YDSXGR_NATIVEDACINVOLR		0x00AE
-#define	YDSXGR_BUF441OUTVOL		0x00B0
-#define	YDSXGR_BUF441OUTVOLL		0x00B0
-#define	YDSXGR_BUF441OUTVOLR		0x00B2
-#define	YDSXGR_BUF441LOOPVOL		0x00B4
-#define	YDSXGR_BUF441LOOPVOLL		0x00B4
-#define	YDSXGR_BUF441LOOPVOLR		0x00B6
-#define	YDSXGR_SPDIFOUTVOL2		0x00B8
-#define	YDSXGR_SPDIFOUTVOL2L		0x00B8
-#define	YDSXGR_SPDIFOUTVOL2R		0x00BA
-#define	YDSXGR_SPDIFLOOPVOL2		0x00BC
-#define	YDSXGR_SPDIFLOOPVOL2L		0x00BC
-#define	YDSXGR_SPDIFLOOPVOL2R		0x00BE
-#define	YDSXGR_ADCSLOTSR		0x00C0
-#define	YDSXGR_RECSLOTSR		0x00C4
-#define	YDSXGR_ADCFORMAT		0x00C8
-#define	YDSXGR_RECFORMAT		0x00CC
-#define	YDSXGR_P44SLOTSR		0x00D0
-#define	YDSXGR_STATUS			0x0100
-#define	YDSXGR_CTRLSELECT		0x0104
-#define	YDSXGR_MODE			0x0108
-#define	YDSXGR_SAMPLECOUNT		0x010C
-#define	YDSXGR_NUMOFSAMPLES		0x0110
-#define	YDSXGR_CONFIG			0x0114
-#define	YDSXGR_PLAYCTRLSIZE		0x0140
-#define	YDSXGR_RECCTRLSIZE		0x0144
-#define	YDSXGR_EFFCTRLSIZE		0x0148
-#define	YDSXGR_WORKSIZE			0x014C
-#define	YDSXGR_MAPOFREC			0x0150
-#define	YDSXGR_MAPOFEFFECT		0x0154
-#define	YDSXGR_PLAYCTRLBASE		0x0158
-#define	YDSXGR_RECCTRLBASE		0x015C
-#define	YDSXGR_EFFCTRLBASE		0x0160
-#define	YDSXGR_WORKBASE			0x0164
-#define	YDSXGR_DSPINSTRAM		0x1000
-#define	YDSXGR_CTRLINSTRAM		0x4000
-
-#define YDSXG_AC97READCMD		0x8000
-#define YDSXG_AC97WRITECMD		0x0000
-
-#define PCIR_LEGCTRL			0x40
-#define PCIR_ELEGCTRL			0x42
-#define PCIR_DSXGCTRL			0x48
-#define PCIR_DSXPWRCTRL1		0x4a
-#define PCIR_DSXPWRCTRL2		0x4e
-#define PCIR_OPLADR			0x60
-#define PCIR_SBADR			0x62
-#define PCIR_MPUADR			0x64
-
-#define YDSXG_DSPLENGTH			0x0080
-#define YDSXG_CTRLLENGTH		0x3000
-
-#define YDSXG_DEFAULT_WORK_SIZE		0x0400
-
-#define YDSXG_PLAYBACK_VOICES		64
-#define YDSXG_CAPTURE_VOICES		2
-#define YDSXG_EFFECT_VOICES		5
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97		2
-
-#define YMF_SAMPF			256	/* Samples per frame @48000 */
-
-/*
- * The slot/voice control bank (2 of these per voice)
- */
-
-typedef struct stru_ymfpci_playback_bank {
-	u32 format;
-	u32 loop_default;
-	u32 base;			/* 32-bit address */
-	u32 loop_start;			/* 32-bit offset */
-	u32 loop_end;			/* 32-bit offset */
-	u32 loop_frac;			/* 8-bit fraction - loop_start */
-	u32 delta_end;			/* pitch delta end */
-	u32 lpfK_end;
-	u32 eg_gain_end;
-	u32 left_gain_end;
-	u32 right_gain_end;
-	u32 eff1_gain_end;
-	u32 eff2_gain_end;
-	u32 eff3_gain_end;
-	u32 lpfQ;
-	u32 status;		/* P3: Always 0 for some reason. */
-	u32 num_of_frames;
-	u32 loop_count;
-	u32 start;		/* P3: J. reads this to know where chip is. */
-	u32 start_frac;
-	u32 delta;
-	u32 lpfK;
-	u32 eg_gain;
-	u32 left_gain;
-	u32 right_gain;
-	u32 eff1_gain;
-	u32 eff2_gain;
-	u32 eff3_gain;
-	u32 lpfD1;
-	u32 lpfD2;
-} ymfpci_playback_bank_t;
-
-typedef struct stru_ymfpci_capture_bank {
-	u32 base;			/* 32-bit address (aligned at 4) */
-	u32 loop_end;			/* size in BYTES (aligned at 4) */
-	u32 start;			/* 32-bit offset */
-	u32 num_of_loops;		/* counter */
-} ymfpci_capture_bank_t;
-
-typedef struct stru_ymfpci_effect_bank {
-	u32 base;			/* 32-bit address */
-	u32 loop_end;			/* 32-bit offset */
-	u32 start;			/* 32-bit offset */
-	u32 temp;
-} ymfpci_effect_bank_t;
-
-typedef struct ymf_voice ymfpci_voice_t;
-/*
- * Throughout the code Yaroslav names YMF unit pointer "codec"
- * even though it does not correspond to any codec. Must be historic.
- * We replace it with "unit" over time.
- * AC97 parts use "codec" to denote a codec, naturally.
- */
-typedef struct ymf_unit ymfpci_t;
-
-typedef enum {
-	YMFPCI_PCM,
-	YMFPCI_SYNTH,
-	YMFPCI_MIDI
-} ymfpci_voice_type_t;
-
-struct ymf_voice {
-	// ymfpci_t *codec;
-	int number;
-	char use, pcm, synth, midi;	// bool
-	ymfpci_playback_bank_t *bank;
-	struct ymf_pcm *ypcm;
-	dma_addr_t bank_ba;
-};
-
-struct ymf_capture {
-	// struct ymf_unit *unit;
-	int use;
-	ymfpci_capture_bank_t *bank;
-	struct ymf_pcm *ypcm;
-};
-
-struct ymf_unit {
-	u8 rev;				/* PCI revision */
-	void __iomem *reg_area_virt;
-	void *dma_area_va;
-	dma_addr_t dma_area_ba;
-	unsigned int dma_area_size;
-
-	dma_addr_t bank_base_capture;
-	dma_addr_t bank_base_effect;
-	dma_addr_t work_base;
-	unsigned int work_size;
-
-	u32 *ctrl_playback;
-	dma_addr_t ctrl_playback_ba;
-	ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
-	ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2];
-	ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
-
-	int start_count;
-	int suspended;
-
-	u32 active_bank;
-	struct ymf_voice voices[YDSXG_PLAYBACK_VOICES];
-	struct ymf_capture capture[YDSXG_CAPTURE_VOICES];
-
-	struct ac97_codec *ac97_codec[NR_AC97];
-	u16 ac97_features;
-
-	struct pci_dev *pci;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-	/* legacy hardware resources */
-	unsigned int iosynth, iomidi;
-	struct address_info opl3_data, mpu_data;
-#endif
-
-	spinlock_t reg_lock;
-	spinlock_t voice_lock;
-	spinlock_t ac97_lock;
-
-	/* soundcore stuff */
-	int dev_audio;
-	struct mutex open_mutex;
-
-	struct list_head ymf_devs;
-	struct list_head states;	/* List of states for this unit */
-};
-
-struct ymf_dmabuf {
-	dma_addr_t dma_addr;
-	void *rawbuf;
-	unsigned buforder;
-
-	/* OSS buffer management stuff */
-	unsigned numfrag;
-	unsigned fragshift;
-
-	/* our buffer acts like a circular ring */
-	unsigned hwptr;		/* where dma last started */
-	unsigned swptr;		/* where driver last clear/filled */
-	int count;		/* fill count */
-	unsigned total_bytes;	/* total bytes dmaed by hardware */
-
-	wait_queue_head_t wait;	/* put process on wait queue when no more space in buffer */
-
-	/* redundant, but makes calculations easier */
-	unsigned fragsize;
-	unsigned dmasize;	/* Total rawbuf[] size */
-
-	/* OSS stuff */
-	unsigned mapped:1;
-	unsigned ready:1;
-	unsigned ossfragshift;
-	int ossmaxfrags;
-	unsigned subdivision;
-};
-
-struct ymf_pcm_format {
-	int format;			/* OSS format */
-	int rate;			/* rate in Hz */
-	int voices;			/* number of voices */
-	int shift;			/* redundant, computed from the above */
-};
-
-typedef enum {
-	PLAYBACK_VOICE,
-	CAPTURE_REC,
-	CAPTURE_AC97,
-	EFFECT_DRY_LEFT,
-	EFFECT_DRY_RIGHT,
-	EFFECT_EFF1,
-	EFFECT_EFF2,
-	EFFECT_EFF3
-} ymfpci_pcm_type_t;
-
-/* This is variant record, but we hate unions. Little waste on pointers []. */
-struct ymf_pcm {
-	ymfpci_pcm_type_t type;
-	struct ymf_state *state;
-
-	ymfpci_voice_t *voices[2];
-	int capture_bank_number;
-
-	struct ymf_dmabuf dmabuf;
-	int running;
-	int spdif;
-};
-
-/*
- * "Software" or virtual channel, an instance of opened /dev/dsp.
- * It may have two physical channels (pcms) for duplex operations.
- */
-
-struct ymf_state {
-	struct list_head chain;
-	struct ymf_unit *unit;			/* backpointer */
-	struct ymf_pcm rpcm, wpcm;
-	struct ymf_pcm_format format;
-};
-
-#endif				/* __YMFPCI_H */
diff --git a/sound/oss/ymfpci_image.h b/sound/oss/ymfpci_image.h
deleted file mode 100644
index 112f2ff..0000000
--- a/sound/oss/ymfpci_image.h
+++ /dev/null
@@ -1,1565 +0,0 @@
-#ifndef _HWMCODE_
-#define _HWMCODE_
-
-static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
-	0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
-	0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
-	0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
-	0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000,
-	0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-
-static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
-	0x000007, 0x240007, 0x0C0007, 0x1C0007,
-	0x060007, 0x700002, 0x000020, 0x030040,
-	0x007104, 0x004286, 0x030040, 0x000F0D,
-	0x000810, 0x20043A, 0x000282, 0x00020D,
-	0x000810, 0x20043A, 0x001282, 0x200E82,
-	0x001A82, 0x032D0D, 0x000810, 0x10043A,
-	0x02D38D, 0x000810, 0x18043A, 0x00010D,
-	0x020015, 0x0000FD, 0x000020, 0x038860,
-	0x039060, 0x038060, 0x038040, 0x038040,
-	0x038040, 0x018040, 0x000A7D, 0x038040,
-	0x038040, 0x018040, 0x200402, 0x000882,
-	0x08001A, 0x000904, 0x015986, 0x000007,
-	0x260007, 0x000007, 0x000007, 0x018A06,
-	0x000007, 0x030C8D, 0x000810, 0x18043A,
-	0x260007, 0x00087D, 0x018042, 0x00160A,
-	0x04A206, 0x000007, 0x00218D, 0x000810,
-	0x08043A, 0x21C206, 0x000007, 0x0007FD,
-	0x018042, 0x08000A, 0x000904, 0x029386,
-	0x000195, 0x090D04, 0x000007, 0x000820,
-	0x0000F5, 0x000B7D, 0x01F060, 0x0000FD,
-	0x032206, 0x018040, 0x000A7D, 0x038042,
-	0x13804A, 0x18000A, 0x001820, 0x059060,
-	0x058860, 0x018040, 0x0000FD, 0x018042,
-	0x70000A, 0x000115, 0x071144, 0x032386,
-	0x030000, 0x007020, 0x034A06, 0x018040,
-	0x00348D, 0x000810, 0x08043A, 0x21EA06,
-	0x000007, 0x02D38D, 0x000810, 0x18043A,
-	0x018206, 0x000007, 0x240007, 0x000F8D,
-	0x000810, 0x00163A, 0x002402, 0x005C02,
-	0x0028FD, 0x000020, 0x018040, 0x08000D,
-	0x000815, 0x510984, 0x000007, 0x00004D,
-	0x000E5D, 0x000E02, 0x00418D, 0x000810,
-	0x08043A, 0x2C8A06, 0x000007, 0x00008D,
-	0x000924, 0x000F02, 0x00458D, 0x000810,
-	0x08043A, 0x2C8A06, 0x000007, 0x00387D,
-	0x018042, 0x08000A, 0x001015, 0x010984,
-	0x018386, 0x000007, 0x01AA06, 0x000007,
-	0x0008FD, 0x018042, 0x18000A, 0x001904,
-	0x218086, 0x280007, 0x001810, 0x28043A,
-	0x280C02, 0x00000D, 0x000810, 0x28143A,
-	0x08808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00020D, 0x189904, 0x000007,
-	0x00402D, 0x0000BD, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x055A86, 0x000007,
-	0x000100, 0x000A20, 0x00047D, 0x018040,
-	0x018042, 0x20000A, 0x003015, 0x012144,
-	0x034986, 0x000007, 0x002104, 0x034986,
-	0x000007, 0x000F8D, 0x000810, 0x280C3A,
-	0x023944, 0x06C986, 0x000007, 0x001810,
-	0x28043A, 0x08810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x002810, 0x78003A,
-	0x00688D, 0x000810, 0x08043A, 0x288A06,
-	0x000007, 0x00400D, 0x001015, 0x189904,
-	0x292904, 0x393904, 0x000007, 0x060206,
-	0x000007, 0x0004F5, 0x00007D, 0x000020,
-	0x00008D, 0x010860, 0x018040, 0x00047D,
-	0x038042, 0x21804A, 0x18000A, 0x021944,
-	0x215886, 0x000007, 0x004075, 0x71F104,
-	0x000007, 0x010042, 0x28000A, 0x002904,
-	0x212086, 0x000007, 0x003C0D, 0x30A904,
-	0x000007, 0x00077D, 0x018042, 0x08000A,
-	0x000904, 0x07DA86, 0x00057D, 0x002820,
-	0x03B060, 0x07F206, 0x018040, 0x003020,
-	0x03A860, 0x018040, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x07FA86, 0x000007,
-	0x00057D, 0x018042, 0x28040A, 0x000E8D,
-	0x000810, 0x280C3A, 0x00000D, 0x000810,
-	0x28143A, 0x09000D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x003DFD, 0x000020,
-	0x018040, 0x00107D, 0x008D8D, 0x000810,
-	0x08043A, 0x288A06, 0x000007, 0x000815,
-	0x08001A, 0x010984, 0x095186, 0x00137D,
-	0x200500, 0x280F20, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x038A60, 0x018040, 0x007FBD, 0x383DC4,
-	0x000007, 0x001A7D, 0x001375, 0x018042,
-	0x09004A, 0x10000A, 0x0B8D04, 0x139504,
-	0x000007, 0x000820, 0x019060, 0x001104,
-	0x212086, 0x010040, 0x0017FD, 0x018042,
-	0x08000A, 0x000904, 0x212286, 0x000007,
-	0x00197D, 0x038042, 0x09804A, 0x10000A,
-	0x000924, 0x001664, 0x0011FD, 0x038042,
-	0x2B804A, 0x19804A, 0x00008D, 0x218944,
-	0x000007, 0x002244, 0x0AE186, 0x000007,
-	0x001A64, 0x002A24, 0x00197D, 0x080102,
-	0x100122, 0x000820, 0x039060, 0x018040,
-	0x003DFD, 0x00008D, 0x000820, 0x018040,
-	0x001375, 0x001A7D, 0x010042, 0x09804A,
-	0x10000A, 0x00021D, 0x0189E4, 0x2992E4,
-	0x309144, 0x000007, 0x00060D, 0x000A15,
-	0x000C1D, 0x001025, 0x00A9E4, 0x012BE4,
-	0x000464, 0x01B3E4, 0x0232E4, 0x000464,
-	0x000464, 0x000464, 0x000464, 0x00040D,
-	0x08B1C4, 0x000007, 0x000820, 0x000BF5,
-	0x030040, 0x00197D, 0x038042, 0x09804A,
-	0x000A24, 0x08000A, 0x080E64, 0x000007,
-	0x100122, 0x000820, 0x031060, 0x010040,
-	0x0064AC, 0x00027D, 0x000020, 0x018040,
-	0x00107D, 0x018042, 0x0011FD, 0x3B804A,
-	0x09804A, 0x20000A, 0x000095, 0x1A1144,
-	0x00A144, 0x0D2086, 0x00040D, 0x00B984,
-	0x0D2186, 0x0018FD, 0x018042, 0x0010FD,
-	0x09804A, 0x28000A, 0x000095, 0x010924,
-	0x002A64, 0x0D1186, 0x000007, 0x002904,
-	0x0D2286, 0x000007, 0x0D2A06, 0x080002,
-	0x00008D, 0x00387D, 0x000820, 0x018040,
-	0x00127D, 0x018042, 0x10000A, 0x003904,
-	0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984,
-	0x0DA186, 0x000025, 0x0E7A06, 0x00002D,
-	0x000015, 0x00082D, 0x02C78D, 0x000820,
-	0x0EC206, 0x00000D, 0x7F8035, 0x00B984,
-	0x0E7186, 0x400025, 0x00008D, 0x110944,
-	0x000007, 0x00018D, 0x109504, 0x000007,
-	0x009164, 0x000424, 0x000424, 0x000424,
-	0x100102, 0x280002, 0x02C68D, 0x000820,
-	0x0EC206, 0x00018D, 0x00042D, 0x00008D,
-	0x109504, 0x000007, 0x00020D, 0x109184,
-	0x000007, 0x02C70D, 0x000820, 0x00008D,
-	0x0038FD, 0x018040, 0x003BFD, 0x001020,
-	0x03A860, 0x000815, 0x313184, 0x212184,
-	0x000007, 0x03B060, 0x03A060, 0x018040,
-	0x0022FD, 0x000095, 0x010924, 0x000424,
-	0x000424, 0x001264, 0x100102, 0x000820,
-	0x039060, 0x018040, 0x001924, 0x00FB8D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x000424,
-	0x000424, 0x00117D, 0x018042, 0x08000A,
-	0x000A24, 0x280502, 0x280C02, 0x09800D,
-	0x000820, 0x0002FD, 0x018040, 0x200007,
-	0x0022FD, 0x018042, 0x08000A, 0x000095,
-	0x280DC4, 0x011924, 0x00197D, 0x018042,
-	0x0011FD, 0x09804A, 0x10000A, 0x0000B5,
-	0x113144, 0x0A8D04, 0x000007, 0x080A44,
-	0x129504, 0x000007, 0x0023FD, 0x001020,
-	0x038040, 0x101244, 0x000007, 0x000820,
-	0x039060, 0x018040, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x10FA86, 0x000007,
-	0x003BFD, 0x000100, 0x000A10, 0x0B807A,
-	0x13804A, 0x090984, 0x000007, 0x000095,
-	0x013D04, 0x118086, 0x10000A, 0x100002,
-	0x090984, 0x000007, 0x038042, 0x11804A,
-	0x090D04, 0x000007, 0x10000A, 0x090D84,
-	0x000007, 0x00257D, 0x000820, 0x018040,
-	0x00010D, 0x000810, 0x28143A, 0x00127D,
-	0x018042, 0x20000A, 0x00197D, 0x018042,
-	0x00117D, 0x31804A, 0x10000A, 0x003124,
-	0x01280D, 0x00397D, 0x000820, 0x058040,
-	0x038042, 0x09844A, 0x000606, 0x08040A,
-	0x300102, 0x003124, 0x000424, 0x000424,
-	0x001224, 0x280502, 0x001A4C, 0x130186,
-	0x700002, 0x00002D, 0x030000, 0x00387D,
-	0x018042, 0x10000A, 0x132A06, 0x002124,
-	0x0000AD, 0x100002, 0x00010D, 0x000924,
-	0x006B24, 0x01368D, 0x00397D, 0x000820,
-	0x058040, 0x038042, 0x09844A, 0x000606,
-	0x08040A, 0x003264, 0x00008D, 0x000A24,
-	0x001020, 0x00227D, 0x018040, 0x013C0D,
-	0x000810, 0x08043A, 0x29D206, 0x000007,
-	0x002820, 0x00207D, 0x018040, 0x00117D,
-	0x038042, 0x13804A, 0x33800A, 0x00387D,
-	0x018042, 0x08000A, 0x000904, 0x163A86,
-	0x000007, 0x00008D, 0x030964, 0x01478D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x380102,
-	0x000424, 0x000424, 0x001224, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x14A286,
-	0x000007, 0x280502, 0x001A4C, 0x163986,
-	0x000007, 0x032164, 0x00632C, 0x003DFD,
-	0x018042, 0x08000A, 0x000095, 0x090904,
-	0x000007, 0x000820, 0x001A4C, 0x156186,
-	0x018040, 0x030000, 0x157A06, 0x002124,
-	0x00010D, 0x000924, 0x006B24, 0x015B8D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x003A64,
-	0x000095, 0x001224, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x15DA86, 0x000007,
-	0x01628D, 0x000810, 0x08043A, 0x29D206,
-	0x000007, 0x14D206, 0x000007, 0x007020,
-	0x08010A, 0x10012A, 0x0020FD, 0x038860,
-	0x039060, 0x018040, 0x00227D, 0x018042,
-	0x003DFD, 0x08000A, 0x31844A, 0x000904,
-	0x16D886, 0x18008B, 0x00008D, 0x189904,
-	0x00312C, 0x17AA06, 0x000007, 0x00324C,
-	0x173386, 0x000007, 0x001904, 0x173086,
-	0x000007, 0x000095, 0x199144, 0x00222C,
-	0x003124, 0x00636C, 0x000E3D, 0x001375,
-	0x000BFD, 0x010042, 0x09804A, 0x10000A,
-	0x038AEC, 0x0393EC, 0x00224C, 0x17A986,
-	0x000007, 0x00008D, 0x189904, 0x00226C,
-	0x00322C, 0x30050A, 0x301DAB, 0x002083,
-	0x0018FD, 0x018042, 0x08000A, 0x018924,
-	0x300502, 0x001083, 0x001875, 0x010042,
-	0x10000A, 0x00008D, 0x010924, 0x001375,
-	0x330542, 0x330CCB, 0x332CCB, 0x3334CB,
-	0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB,
-	0x305C8B, 0x006083, 0x0002F5, 0x010042,
-	0x08000A, 0x000904, 0x187A86, 0x000007,
-	0x001E2D, 0x0005FD, 0x018042, 0x08000A,
-	0x028924, 0x280502, 0x00060D, 0x000810,
-	0x280C3A, 0x00008D, 0x000810, 0x28143A,
-	0x0A808D, 0x000820, 0x0002F5, 0x010040,
-	0x220007, 0x001275, 0x030042, 0x21004A,
-	0x00008D, 0x1A0944, 0x000007, 0x01980D,
-	0x000810, 0x08043A, 0x2B2206, 0x000007,
-	0x0001F5, 0x030042, 0x0D004A, 0x10000A,
-	0x089144, 0x000007, 0x000820, 0x010040,
-	0x0025F5, 0x0A3144, 0x000007, 0x000820,
-	0x032860, 0x030040, 0x00217D, 0x038042,
-	0x0B804A, 0x10000A, 0x000820, 0x031060,
-	0x030040, 0x00008D, 0x000124, 0x00012C,
-	0x000E64, 0x001A64, 0x00636C, 0x08010A,
-	0x10012A, 0x000820, 0x031060, 0x030040,
-	0x0020FD, 0x018042, 0x08000A, 0x00227D,
-	0x018042, 0x10000A, 0x000820, 0x031060,
-	0x030040, 0x00197D, 0x018042, 0x08000A,
-	0x0022FD, 0x038042, 0x10000A, 0x000820,
-	0x031060, 0x030040, 0x090D04, 0x000007,
-	0x000820, 0x030040, 0x038042, 0x0B804A,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x038042, 0x13804A, 0x19804A, 0x110D04,
-	0x198D04, 0x000007, 0x08000A, 0x001020,
-	0x031860, 0x030860, 0x030040, 0x00008D,
-	0x0B0944, 0x000007, 0x000820, 0x010040,
-	0x0005F5, 0x030042, 0x08000A, 0x000820,
-	0x010040, 0x0000F5, 0x010042, 0x08000A,
-	0x000904, 0x1C6086, 0x001E75, 0x030042,
-	0x01044A, 0x000C0A, 0x1C7206, 0x000007,
-	0x000402, 0x000C02, 0x00177D, 0x001AF5,
-	0x018042, 0x03144A, 0x031C4A, 0x03244A,
-	0x032C4A, 0x03344A, 0x033C4A, 0x03444A,
-	0x004C0A, 0x00043D, 0x0013F5, 0x001AFD,
-	0x030042, 0x0B004A, 0x1B804A, 0x13804A,
-	0x20000A, 0x089144, 0x19A144, 0x0389E4,
-	0x0399EC, 0x005502, 0x005D0A, 0x030042,
-	0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
-	0x089144, 0x19A144, 0x0389E4, 0x0399EC,
-	0x006502, 0x006D0A, 0x030042, 0x0B004A,
-	0x19004A, 0x2B804A, 0x13804A, 0x21804A,
-	0x30000A, 0x089144, 0x19A144, 0x2AB144,
-	0x0389E4, 0x0399EC, 0x007502, 0x007D0A,
-	0x03A9E4, 0x000702, 0x00107D, 0x000415,
-	0x018042, 0x08000A, 0x0109E4, 0x000F02,
-	0x002AF5, 0x0019FD, 0x010042, 0x09804A,
-	0x10000A, 0x000934, 0x001674, 0x0029F5,
-	0x010042, 0x10000A, 0x00917C, 0x002075,
-	0x010042, 0x08000A, 0x000904, 0x1ED286,
-	0x0026F5, 0x0027F5, 0x030042, 0x09004A,
-	0x10000A, 0x000A3C, 0x00167C, 0x001A75,
-	0x000BFD, 0x010042, 0x51804A, 0x48000A,
-	0x160007, 0x001075, 0x010042, 0x282C0A,
-	0x281D12, 0x282512, 0x001F32, 0x1E0007,
-	0x0E0007, 0x001975, 0x010042, 0x002DF5,
-	0x0D004A, 0x10000A, 0x009144, 0x1FB286,
-	0x010042, 0x28340A, 0x000E5D, 0x00008D,
-	0x000375, 0x000820, 0x010040, 0x05D2F4,
-	0x54D104, 0x00735C, 0x205386, 0x000007,
-	0x0C0007, 0x080007, 0x0A0007, 0x02040D,
-	0x000810, 0x08043A, 0x332206, 0x000007,
-	0x205A06, 0x000007, 0x080007, 0x002275,
-	0x010042, 0x20000A, 0x002104, 0x212086,
-	0x001E2D, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x209286, 0x000007, 0x002010,
-	0x30043A, 0x00057D, 0x0180C3, 0x08000A,
-	0x028924, 0x280502, 0x280C02, 0x0A810D,
-	0x000820, 0x0002F5, 0x010040, 0x220007,
-	0x0004FD, 0x018042, 0x70000A, 0x030000,
-	0x007020, 0x06FA06, 0x018040, 0x02180D,
-	0x000810, 0x08043A, 0x2B2206, 0x000007,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x218A86, 0x000007, 0x01F206, 0x000007,
-	0x000875, 0x0009FD, 0x00010D, 0x220A06,
-	0x000295, 0x000B75, 0x00097D, 0x00000D,
-	0x000515, 0x010042, 0x18000A, 0x001904,
-	0x287886, 0x0006F5, 0x001020, 0x010040,
-	0x0004F5, 0x000820, 0x010040, 0x000775,
-	0x010042, 0x09804A, 0x10000A, 0x001124,
-	0x000904, 0x22BA86, 0x000815, 0x080102,
-	0x101204, 0x22DA06, 0x000575, 0x081204,
-	0x000007, 0x100102, 0x000575, 0x000425,
-	0x021124, 0x100102, 0x000820, 0x031060,
-	0x010040, 0x001924, 0x287886, 0x00008D,
-	0x000464, 0x009D04, 0x278886, 0x180102,
-	0x000575, 0x010042, 0x28040A, 0x00018D,
-	0x000924, 0x280D02, 0x00000D, 0x000924,
-	0x281502, 0x10000D, 0x000820, 0x0002F5,
-	0x010040, 0x200007, 0x001175, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x23C286,
-	0x000007, 0x000100, 0x080B20, 0x130B60,
-	0x1B0B60, 0x030A60, 0x010040, 0x050042,
-	0x3D004A, 0x35004A, 0x2D004A, 0x20000A,
-	0x0006F5, 0x010042, 0x28140A, 0x0004F5,
-	0x010042, 0x08000A, 0x000315, 0x010D04,
-	0x24CA86, 0x004015, 0x000095, 0x010D04,
-	0x24B886, 0x100022, 0x10002A, 0x24E206,
-	0x000007, 0x333104, 0x2AA904, 0x000007,
-	0x032124, 0x280502, 0x001124, 0x000424,
-	0x000424, 0x003224, 0x00292C, 0x00636C,
-	0x25F386, 0x000007, 0x02B164, 0x000464,
-	0x000464, 0x00008D, 0x000A64, 0x280D02,
-	0x10008D, 0x000820, 0x0002F5, 0x010040,
-	0x220007, 0x00008D, 0x38B904, 0x000007,
-	0x03296C, 0x30010A, 0x0002F5, 0x010042,
-	0x08000A, 0x000904, 0x25BA86, 0x000007,
-	0x02312C, 0x28050A, 0x00008D, 0x01096C,
-	0x280D0A, 0x10010D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x001124, 0x000424,
-	0x000424, 0x003224, 0x300102, 0x032944,
-	0x267A86, 0x000007, 0x300002, 0x0004F5,
-	0x010042, 0x08000A, 0x000315, 0x010D04,
-	0x26C086, 0x003124, 0x000464, 0x300102,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x26CA86, 0x000007, 0x003124, 0x300502,
-	0x003924, 0x300583, 0x000883, 0x0005F5,
-	0x010042, 0x28040A, 0x00008D, 0x008124,
-	0x280D02, 0x00008D, 0x008124, 0x281502,
-	0x10018D, 0x000820, 0x0002F5, 0x010040,
-	0x220007, 0x001025, 0x000575, 0x030042,
-	0x09004A, 0x10000A, 0x0A0904, 0x121104,
-	0x000007, 0x001020, 0x050860, 0x050040,
-	0x0006FD, 0x018042, 0x09004A, 0x10000A,
-	0x0000A5, 0x0A0904, 0x121104, 0x000007,
-	0x000820, 0x019060, 0x010040, 0x0002F5,
-	0x010042, 0x08000A, 0x000904, 0x284286,
-	0x000007, 0x230A06, 0x000007, 0x000606,
-	0x000007, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x289286, 0x000007, 0x000100,
-	0x080B20, 0x138B60, 0x1B8B60, 0x238B60,
-	0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60,
-	0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60,
-	0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60,
-	0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60,
-	0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60,
-	0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60,
-	0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60,
-	0x000606, 0x018040, 0x00008D, 0x000A64,
-	0x280D02, 0x000A24, 0x00027D, 0x018042,
-	0x10000A, 0x001224, 0x0003FD, 0x018042,
-	0x08000A, 0x000904, 0x2A8286, 0x000007,
-	0x00018D, 0x000A24, 0x000464, 0x000464,
-	0x080102, 0x000924, 0x000424, 0x000424,
-	0x100102, 0x02000D, 0x009144, 0x2AD986,
-	0x000007, 0x0001FD, 0x018042, 0x08000A,
-	0x000A44, 0x2ABB86, 0x018042, 0x0A000D,
-	0x000820, 0x0002FD, 0x018040, 0x200007,
-	0x00027D, 0x001020, 0x000606, 0x018040,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x2B2A86, 0x000007, 0x00037D, 0x018042,
-	0x08000A, 0x000904, 0x2B5A86, 0x000007,
-	0x000075, 0x002E7D, 0x010042, 0x0B804A,
-	0x000020, 0x000904, 0x000686, 0x010040,
-	0x31844A, 0x30048B, 0x000883, 0x00008D,
-	0x000810, 0x28143A, 0x00008D, 0x000810,
-	0x280C3A, 0x000675, 0x010042, 0x08000A,
-	0x003815, 0x010924, 0x280502, 0x0B000D,
-	0x000820, 0x0002F5, 0x010040, 0x000606,
-	0x220007, 0x000464, 0x000464, 0x000606,
-	0x000007, 0x000134, 0x007F8D, 0x00093C,
-	0x281D12, 0x282512, 0x001F32, 0x0E0007,
-	0x00010D, 0x00037D, 0x000820, 0x018040,
-	0x05D2F4, 0x000007, 0x080007, 0x00037D,
-	0x018042, 0x08000A, 0x000904, 0x2D0286,
-	0x000007, 0x000606, 0x000007, 0x000007,
-	0x000012, 0x100007, 0x320007, 0x600007,
-	0x100080, 0x48001A, 0x004904, 0x2D6186,
-	0x000007, 0x001210, 0x58003A, 0x000145,
-	0x5C5D04, 0x000007, 0x000080, 0x48001A,
-	0x004904, 0x2DB186, 0x000007, 0x001210,
-	0x50003A, 0x005904, 0x2E0886, 0x000045,
-	0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524,
-	0x004224, 0x500102, 0x200502, 0x000082,
-	0x40001A, 0x004104, 0x2E3986, 0x000007,
-	0x003865, 0x40001A, 0x004020, 0x00104D,
-	0x04C184, 0x301B86, 0x000040, 0x040007,
-	0x000165, 0x000145, 0x004020, 0x000040,
-	0x000765, 0x080080, 0x40001A, 0x004104,
-	0x2EC986, 0x000007, 0x001210, 0x40003A,
-	0x004104, 0x2F2286, 0x00004D, 0x0000CD,
-	0x004810, 0x20043A, 0x000882, 0x40001A,
-	0x004104, 0x2F3186, 0x000007, 0x004820,
-	0x005904, 0x300886, 0x000040, 0x0007E5,
-	0x200480, 0x2816A0, 0x3216E0, 0x3A16E0,
-	0x4216E0, 0x021260, 0x000040, 0x000032,
-	0x400075, 0x00007D, 0x07D574, 0x200512,
-	0x000082, 0x40001A, 0x004104, 0x2FE186,
-	0x000007, 0x037206, 0x640007, 0x060007,
-	0x0000E5, 0x000020, 0x000040, 0x000A65,
-	0x000020, 0x020040, 0x020040, 0x000040,
-	0x000165, 0x000042, 0x70000A, 0x007104,
-	0x30A286, 0x000007, 0x018206, 0x640007,
-	0x050000, 0x007020, 0x000040, 0x037206,
-	0x640007, 0x000007, 0x00306D, 0x028860,
-	0x029060, 0x08000A, 0x028860, 0x008040,
-	0x100012, 0x00100D, 0x009184, 0x314186,
-	0x000E0D, 0x009184, 0x325186, 0x000007,
-	0x300007, 0x001020, 0x003B6D, 0x008040,
-	0x000080, 0x08001A, 0x000904, 0x316186,
-	0x000007, 0x001220, 0x000DED, 0x008040,
-	0x008042, 0x10000A, 0x40000D, 0x109544,
-	0x000007, 0x001020, 0x000DED, 0x008040,
-	0x008042, 0x20040A, 0x000082, 0x08001A,
-	0x000904, 0x31F186, 0x000007, 0x003B6D,
-	0x008042, 0x08000A, 0x000E15, 0x010984,
-	0x329B86, 0x600007, 0x08001A, 0x000C15,
-	0x010984, 0x328386, 0x000020, 0x1A0007,
-	0x0002ED, 0x008040, 0x620007, 0x00306D,
-	0x028042, 0x0A804A, 0x000820, 0x0A804A,
-	0x000606, 0x10804A, 0x000007, 0x282512,
-	0x001F32, 0x05D2F4, 0x54D104, 0x00735C,
-	0x000786, 0x000007, 0x0C0007, 0x0A0007,
-	0x1C0007, 0x003465, 0x020040, 0x004820,
-	0x025060, 0x40000A, 0x024060, 0x000040,
-	0x454944, 0x000007, 0x004020, 0x003AE5,
-	0x000040, 0x0028E5, 0x000042, 0x48000A,
-	0x004904, 0x386886, 0x002C65, 0x000042,
-	0x40000A, 0x0000D5, 0x454104, 0x000007,
-	0x000655, 0x054504, 0x34F286, 0x0001D5,
-	0x054504, 0x34F086, 0x002B65, 0x000042,
-	0x003AE5, 0x50004A, 0x40000A, 0x45C3D4,
-	0x000007, 0x454504, 0x000007, 0x0000CD,
-	0x444944, 0x000007, 0x454504, 0x000007,
-	0x00014D, 0x554944, 0x000007, 0x045144,
-	0x34E986, 0x002C65, 0x000042, 0x48000A,
-	0x4CD104, 0x000007, 0x04C144, 0x34F386,
-	0x000007, 0x160007, 0x002CE5, 0x040042,
-	0x40000A, 0x004020, 0x000040, 0x002965,
-	0x000042, 0x40000A, 0x004104, 0x356086,
-	0x000007, 0x002402, 0x36A206, 0x005C02,
-	0x0025E5, 0x000042, 0x40000A, 0x004274,
-	0x002AE5, 0x000042, 0x40000A, 0x004274,
-	0x500112, 0x0029E5, 0x000042, 0x40000A,
-	0x004234, 0x454104, 0x000007, 0x004020,
-	0x000040, 0x003EE5, 0x000020, 0x000040,
-	0x002DE5, 0x400152, 0x50000A, 0x045144,
-	0x364A86, 0x0000C5, 0x003EE5, 0x004020,
-	0x000040, 0x002BE5, 0x000042, 0x40000A,
-	0x404254, 0x000007, 0x002AE5, 0x004020,
-	0x000040, 0x500132, 0x040134, 0x005674,
-	0x0029E5, 0x020042, 0x42000A, 0x000042,
-	0x50000A, 0x05417C, 0x0028E5, 0x000042,
-	0x48000A, 0x0000C5, 0x4CC144, 0x371086,
-	0x0026E5, 0x0027E5, 0x020042, 0x40004A,
-	0x50000A, 0x00423C, 0x00567C, 0x0028E5,
-	0x004820, 0x000040, 0x281D12, 0x282512,
-	0x001F72, 0x002965, 0x000042, 0x40000A,
-	0x004104, 0x37AA86, 0x0E0007, 0x160007,
-	0x1E0007, 0x003EE5, 0x000042, 0x40000A,
-	0x004104, 0x37E886, 0x002D65, 0x000042,
-	0x28340A, 0x003465, 0x020042, 0x42004A,
-	0x004020, 0x4A004A, 0x50004A, 0x05D2F4,
-	0x54D104, 0x00735C, 0x385186, 0x000007,
-	0x000606, 0x080007, 0x0C0007, 0x080007,
-	0x0A0007, 0x0001E5, 0x020045, 0x004020,
-	0x000060, 0x000365, 0x000040, 0x002E65,
-	0x001A20, 0x0A1A60, 0x000040, 0x003465,
-	0x020042, 0x42004A, 0x004020, 0x4A004A,
-	0x000606, 0x50004A, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000
-};
-
-// --------------------------------------------
-//  DS-1E Controller InstructionRAM Code
-//	1999/06/21
-//	Buf441 slot is Enabled.
-// --------------------------------------------
-// 04/09  creat
-// 04/12  stop nise fix
-// 06/21  WorkingOff timming
-static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
-	0x000007, 0x240007, 0x0C0007, 0x1C0007,
-	0x060007, 0x700002, 0x000020, 0x030040,
-	0x007104, 0x004286, 0x030040, 0x000F0D,
-	0x000810, 0x20043A, 0x000282, 0x00020D,
-	0x000810, 0x20043A, 0x001282, 0x200E82,
-	0x00800D, 0x000810, 0x20043A, 0x001A82,
-	0x03460D, 0x000810, 0x10043A, 0x02EC0D,
-	0x000810, 0x18043A, 0x00010D, 0x020015,
-	0x0000FD, 0x000020, 0x038860, 0x039060,
-	0x038060, 0x038040, 0x038040, 0x038040,
-	0x018040, 0x000A7D, 0x038040, 0x038040,
-	0x018040, 0x200402, 0x000882, 0x08001A,
-	0x000904, 0x017186, 0x000007, 0x260007,
-	0x400007, 0x000007, 0x03258D, 0x000810,
-	0x18043A, 0x260007, 0x284402, 0x00087D,
-	0x018042, 0x00160A, 0x05A206, 0x000007,
-	0x440007, 0x00230D, 0x000810, 0x08043A,
-	0x22FA06, 0x000007, 0x0007FD, 0x018042,
-	0x08000A, 0x000904, 0x02AB86, 0x000195,
-	0x090D04, 0x000007, 0x000820, 0x0000F5,
-	0x000B7D, 0x01F060, 0x0000FD, 0x033A06,
-	0x018040, 0x000A7D, 0x038042, 0x13804A,
-	0x18000A, 0x001820, 0x059060, 0x058860,
-	0x018040, 0x0000FD, 0x018042, 0x70000A,
-	0x000115, 0x071144, 0x033B86, 0x030000,
-	0x007020, 0x036206, 0x018040, 0x00360D,
-	0x000810, 0x08043A, 0x232206, 0x000007,
-	0x02EC0D, 0x000810, 0x18043A, 0x019A06,
-	0x000007, 0x240007, 0x000F8D, 0x000810,
-	0x00163A, 0x002402, 0x005C02, 0x0028FD,
-	0x000020, 0x018040, 0x08000D, 0x000815,
-	0x510984, 0x000007, 0x00004D, 0x000E5D,
-	0x000E02, 0x00430D, 0x000810, 0x08043A,
-	0x2E1206, 0x000007, 0x00008D, 0x000924,
-	0x000F02, 0x00470D, 0x000810, 0x08043A,
-	0x2E1206, 0x000007, 0x480480, 0x001210,
-	0x28043A, 0x00778D, 0x000810, 0x280C3A,
-	0x00068D, 0x000810, 0x28143A, 0x284402,
-	0x03258D, 0x000810, 0x18043A, 0x07FF8D,
-	0x000820, 0x0002FD, 0x018040, 0x260007,
-	0x200007, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x051286, 0x000007, 0x240007,
-	0x02EC0D, 0x000810, 0x18043A, 0x00387D,
-	0x018042, 0x08000A, 0x001015, 0x010984,
-	0x019B86, 0x000007, 0x01B206, 0x000007,
-	0x0008FD, 0x018042, 0x18000A, 0x001904,
-	0x22B886, 0x280007, 0x001810, 0x28043A,
-	0x280C02, 0x00000D, 0x000810, 0x28143A,
-	0x08808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00020D, 0x189904, 0x000007,
-	0x00402D, 0x0000BD, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x065A86, 0x000007,
-	0x000100, 0x000A20, 0x00047D, 0x018040,
-	0x018042, 0x20000A, 0x003015, 0x012144,
-	0x036186, 0x000007, 0x002104, 0x036186,
-	0x000007, 0x000F8D, 0x000810, 0x280C3A,
-	0x023944, 0x07C986, 0x000007, 0x001810,
-	0x28043A, 0x08810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x002810, 0x78003A,
-	0x00788D, 0x000810, 0x08043A, 0x2A1206,
-	0x000007, 0x00400D, 0x001015, 0x189904,
-	0x292904, 0x393904, 0x000007, 0x070206,
-	0x000007, 0x0004F5, 0x00007D, 0x000020,
-	0x00008D, 0x010860, 0x018040, 0x00047D,
-	0x038042, 0x21804A, 0x18000A, 0x021944,
-	0x229086, 0x000007, 0x004075, 0x71F104,
-	0x000007, 0x010042, 0x28000A, 0x002904,
-	0x225886, 0x000007, 0x003C0D, 0x30A904,
-	0x000007, 0x00077D, 0x018042, 0x08000A,
-	0x000904, 0x08DA86, 0x00057D, 0x002820,
-	0x03B060, 0x08F206, 0x018040, 0x003020,
-	0x03A860, 0x018040, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x08FA86, 0x000007,
-	0x00057D, 0x018042, 0x28040A, 0x000E8D,
-	0x000810, 0x280C3A, 0x00000D, 0x000810,
-	0x28143A, 0x09000D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x003DFD, 0x000020,
-	0x018040, 0x00107D, 0x009D8D, 0x000810,
-	0x08043A, 0x2A1206, 0x000007, 0x000815,
-	0x08001A, 0x010984, 0x0A5186, 0x00137D,
-	0x200500, 0x280F20, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x038A60, 0x018040, 0x00107D, 0x018042,
-	0x08000A, 0x000215, 0x010984, 0x3A8186,
-	0x000007, 0x007FBD, 0x383DC4, 0x000007,
-	0x001A7D, 0x001375, 0x018042, 0x09004A,
-	0x10000A, 0x0B8D04, 0x139504, 0x000007,
-	0x000820, 0x019060, 0x001104, 0x225886,
-	0x010040, 0x0017FD, 0x018042, 0x08000A,
-	0x000904, 0x225A86, 0x000007, 0x00197D,
-	0x038042, 0x09804A, 0x10000A, 0x000924,
-	0x001664, 0x0011FD, 0x038042, 0x2B804A,
-	0x19804A, 0x00008D, 0x218944, 0x000007,
-	0x002244, 0x0C1986, 0x000007, 0x001A64,
-	0x002A24, 0x00197D, 0x080102, 0x100122,
-	0x000820, 0x039060, 0x018040, 0x003DFD,
-	0x00008D, 0x000820, 0x018040, 0x001375,
-	0x001A7D, 0x010042, 0x09804A, 0x10000A,
-	0x00021D, 0x0189E4, 0x2992E4, 0x309144,
-	0x000007, 0x00060D, 0x000A15, 0x000C1D,
-	0x001025, 0x00A9E4, 0x012BE4, 0x000464,
-	0x01B3E4, 0x0232E4, 0x000464, 0x000464,
-	0x000464, 0x000464, 0x00040D, 0x08B1C4,
-	0x000007, 0x000820, 0x000BF5, 0x030040,
-	0x00197D, 0x038042, 0x09804A, 0x000A24,
-	0x08000A, 0x080E64, 0x000007, 0x100122,
-	0x000820, 0x031060, 0x010040, 0x0064AC,
-	0x00027D, 0x000020, 0x018040, 0x00107D,
-	0x018042, 0x0011FD, 0x3B804A, 0x09804A,
-	0x20000A, 0x000095, 0x1A1144, 0x00A144,
-	0x0E5886, 0x00040D, 0x00B984, 0x0E5986,
-	0x0018FD, 0x018042, 0x0010FD, 0x09804A,
-	0x28000A, 0x000095, 0x010924, 0x002A64,
-	0x0E4986, 0x000007, 0x002904, 0x0E5A86,
-	0x000007, 0x0E6206, 0x080002, 0x00008D,
-	0x00387D, 0x000820, 0x018040, 0x00127D,
-	0x018042, 0x10000A, 0x003904, 0x0F0986,
-	0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986,
-	0x000025, 0x0FB206, 0x00002D, 0x000015,
-	0x00082D, 0x02E00D, 0x000820, 0x0FFA06,
-	0x00000D, 0x7F8035, 0x00B984, 0x0FA986,
-	0x400025, 0x00008D, 0x110944, 0x000007,
-	0x00018D, 0x109504, 0x000007, 0x009164,
-	0x000424, 0x000424, 0x000424, 0x100102,
-	0x280002, 0x02DF0D, 0x000820, 0x0FFA06,
-	0x00018D, 0x00042D, 0x00008D, 0x109504,
-	0x000007, 0x00020D, 0x109184, 0x000007,
-	0x02DF8D, 0x000820, 0x00008D, 0x0038FD,
-	0x018040, 0x003BFD, 0x001020, 0x03A860,
-	0x000815, 0x313184, 0x212184, 0x000007,
-	0x03B060, 0x03A060, 0x018040, 0x0022FD,
-	0x000095, 0x010924, 0x000424, 0x000424,
-	0x001264, 0x100102, 0x000820, 0x039060,
-	0x018040, 0x001924, 0x010F0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x000424, 0x000424,
-	0x00117D, 0x018042, 0x08000A, 0x000A24,
-	0x280502, 0x280C02, 0x09800D, 0x000820,
-	0x0002FD, 0x018040, 0x200007, 0x0022FD,
-	0x018042, 0x08000A, 0x000095, 0x280DC4,
-	0x011924, 0x00197D, 0x018042, 0x0011FD,
-	0x09804A, 0x10000A, 0x0000B5, 0x113144,
-	0x0A8D04, 0x000007, 0x080A44, 0x129504,
-	0x000007, 0x0023FD, 0x001020, 0x038040,
-	0x101244, 0x000007, 0x000820, 0x039060,
-	0x018040, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x123286, 0x000007, 0x003BFD,
-	0x000100, 0x000A10, 0x0B807A, 0x13804A,
-	0x090984, 0x000007, 0x000095, 0x013D04,
-	0x12B886, 0x10000A, 0x100002, 0x090984,
-	0x000007, 0x038042, 0x11804A, 0x090D04,
-	0x000007, 0x10000A, 0x090D84, 0x000007,
-	0x00257D, 0x000820, 0x018040, 0x00010D,
-	0x000810, 0x28143A, 0x00127D, 0x018042,
-	0x20000A, 0x00197D, 0x018042, 0x00117D,
-	0x31804A, 0x10000A, 0x003124, 0x013B8D,
-	0x00397D, 0x000820, 0x058040, 0x038042,
-	0x09844A, 0x000606, 0x08040A, 0x300102,
-	0x003124, 0x000424, 0x000424, 0x001224,
-	0x280502, 0x001A4C, 0x143986, 0x700002,
-	0x00002D, 0x030000, 0x00387D, 0x018042,
-	0x10000A, 0x146206, 0x002124, 0x0000AD,
-	0x100002, 0x00010D, 0x000924, 0x006B24,
-	0x014A0D, 0x00397D, 0x000820, 0x058040,
-	0x038042, 0x09844A, 0x000606, 0x08040A,
-	0x003264, 0x00008D, 0x000A24, 0x001020,
-	0x00227D, 0x018040, 0x014F8D, 0x000810,
-	0x08043A, 0x2B5A06, 0x000007, 0x002820,
-	0x00207D, 0x018040, 0x00117D, 0x038042,
-	0x13804A, 0x33800A, 0x00387D, 0x018042,
-	0x08000A, 0x000904, 0x177286, 0x000007,
-	0x00008D, 0x030964, 0x015B0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x380102, 0x000424,
-	0x000424, 0x001224, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x15DA86, 0x000007,
-	0x280502, 0x001A4C, 0x177186, 0x000007,
-	0x032164, 0x00632C, 0x003DFD, 0x018042,
-	0x08000A, 0x000095, 0x090904, 0x000007,
-	0x000820, 0x001A4C, 0x169986, 0x018040,
-	0x030000, 0x16B206, 0x002124, 0x00010D,
-	0x000924, 0x006B24, 0x016F0D, 0x00397D,
-	0x000820, 0x058040, 0x038042, 0x09844A,
-	0x000606, 0x08040A, 0x003A64, 0x000095,
-	0x001224, 0x0002FD, 0x018042, 0x08000A,
-	0x000904, 0x171286, 0x000007, 0x01760D,
-	0x000810, 0x08043A, 0x2B5A06, 0x000007,
-	0x160A06, 0x000007, 0x007020, 0x08010A,
-	0x10012A, 0x0020FD, 0x038860, 0x039060,
-	0x018040, 0x00227D, 0x018042, 0x003DFD,
-	0x08000A, 0x31844A, 0x000904, 0x181086,
-	0x18008B, 0x00008D, 0x189904, 0x00312C,
-	0x18E206, 0x000007, 0x00324C, 0x186B86,
-	0x000007, 0x001904, 0x186886, 0x000007,
-	0x000095, 0x199144, 0x00222C, 0x003124,
-	0x00636C, 0x000E3D, 0x001375, 0x000BFD,
-	0x010042, 0x09804A, 0x10000A, 0x038AEC,
-	0x0393EC, 0x00224C, 0x18E186, 0x000007,
-	0x00008D, 0x189904, 0x00226C, 0x00322C,
-	0x30050A, 0x301DAB, 0x002083, 0x0018FD,
-	0x018042, 0x08000A, 0x018924, 0x300502,
-	0x001083, 0x001875, 0x010042, 0x10000A,
-	0x00008D, 0x010924, 0x001375, 0x330542,
-	0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB,
-	0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B,
-	0x006083, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x19B286, 0x000007, 0x001E2D,
-	0x0005FD, 0x018042, 0x08000A, 0x028924,
-	0x280502, 0x00060D, 0x000810, 0x280C3A,
-	0x00008D, 0x000810, 0x28143A, 0x0A808D,
-	0x000820, 0x0002F5, 0x010040, 0x220007,
-	0x001275, 0x030042, 0x21004A, 0x00008D,
-	0x1A0944, 0x000007, 0x01AB8D, 0x000810,
-	0x08043A, 0x2CAA06, 0x000007, 0x0001F5,
-	0x030042, 0x0D004A, 0x10000A, 0x089144,
-	0x000007, 0x000820, 0x010040, 0x0025F5,
-	0x0A3144, 0x000007, 0x000820, 0x032860,
-	0x030040, 0x00217D, 0x038042, 0x0B804A,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x00008D, 0x000124, 0x00012C, 0x000E64,
-	0x001A64, 0x00636C, 0x08010A, 0x10012A,
-	0x000820, 0x031060, 0x030040, 0x0020FD,
-	0x018042, 0x08000A, 0x00227D, 0x018042,
-	0x10000A, 0x000820, 0x031060, 0x030040,
-	0x00197D, 0x018042, 0x08000A, 0x0022FD,
-	0x038042, 0x10000A, 0x000820, 0x031060,
-	0x030040, 0x090D04, 0x000007, 0x000820,
-	0x030040, 0x038042, 0x0B804A, 0x10000A,
-	0x000820, 0x031060, 0x030040, 0x038042,
-	0x13804A, 0x19804A, 0x110D04, 0x198D04,
-	0x000007, 0x08000A, 0x001020, 0x031860,
-	0x030860, 0x030040, 0x00008D, 0x0B0944,
-	0x000007, 0x000820, 0x010040, 0x0005F5,
-	0x030042, 0x08000A, 0x000820, 0x010040,
-	0x0000F5, 0x010042, 0x08000A, 0x000904,
-	0x1D9886, 0x001E75, 0x030042, 0x01044A,
-	0x000C0A, 0x1DAA06, 0x000007, 0x000402,
-	0x000C02, 0x00177D, 0x001AF5, 0x018042,
-	0x03144A, 0x031C4A, 0x03244A, 0x032C4A,
-	0x03344A, 0x033C4A, 0x03444A, 0x004C0A,
-	0x00043D, 0x0013F5, 0x001AFD, 0x030042,
-	0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
-	0x089144, 0x19A144, 0x0389E4, 0x0399EC,
-	0x005502, 0x005D0A, 0x030042, 0x0B004A,
-	0x1B804A, 0x13804A, 0x20000A, 0x089144,
-	0x19A144, 0x0389E4, 0x0399EC, 0x006502,
-	0x006D0A, 0x030042, 0x0B004A, 0x19004A,
-	0x2B804A, 0x13804A, 0x21804A, 0x30000A,
-	0x089144, 0x19A144, 0x2AB144, 0x0389E4,
-	0x0399EC, 0x007502, 0x007D0A, 0x03A9E4,
-	0x000702, 0x00107D, 0x000415, 0x018042,
-	0x08000A, 0x0109E4, 0x000F02, 0x002AF5,
-	0x0019FD, 0x010042, 0x09804A, 0x10000A,
-	0x000934, 0x001674, 0x0029F5, 0x010042,
-	0x10000A, 0x00917C, 0x002075, 0x010042,
-	0x08000A, 0x000904, 0x200A86, 0x0026F5,
-	0x0027F5, 0x030042, 0x09004A, 0x10000A,
-	0x000A3C, 0x00167C, 0x001A75, 0x000BFD,
-	0x010042, 0x51804A, 0x48000A, 0x160007,
-	0x001075, 0x010042, 0x282C0A, 0x281D12,
-	0x282512, 0x001F32, 0x1E0007, 0x0E0007,
-	0x001975, 0x010042, 0x002DF5, 0x0D004A,
-	0x10000A, 0x009144, 0x20EA86, 0x010042,
-	0x28340A, 0x000E5D, 0x00008D, 0x000375,
-	0x000820, 0x010040, 0x05D2F4, 0x54D104,
-	0x00735C, 0x218B86, 0x000007, 0x0C0007,
-	0x080007, 0x0A0007, 0x02178D, 0x000810,
-	0x08043A, 0x34B206, 0x000007, 0x219206,
-	0x000007, 0x080007, 0x002275, 0x010042,
-	0x20000A, 0x002104, 0x225886, 0x001E2D,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x21CA86, 0x000007, 0x002010, 0x30043A,
-	0x00057D, 0x0180C3, 0x08000A, 0x028924,
-	0x280502, 0x280C02, 0x0A810D, 0x000820,
-	0x0002F5, 0x010040, 0x220007, 0x0004FD,
-	0x018042, 0x70000A, 0x030000, 0x007020,
-	0x07FA06, 0x018040, 0x022B8D, 0x000810,
-	0x08043A, 0x2CAA06, 0x000007, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x22C286,
-	0x000007, 0x020206, 0x000007, 0x000875,
-	0x0009FD, 0x00010D, 0x234206, 0x000295,
-	0x000B75, 0x00097D, 0x00000D, 0x000515,
-	0x010042, 0x18000A, 0x001904, 0x2A0086,
-	0x0006F5, 0x001020, 0x010040, 0x0004F5,
-	0x000820, 0x010040, 0x000775, 0x010042,
-	0x09804A, 0x10000A, 0x001124, 0x000904,
-	0x23F286, 0x000815, 0x080102, 0x101204,
-	0x241206, 0x000575, 0x081204, 0x000007,
-	0x100102, 0x000575, 0x000425, 0x021124,
-	0x100102, 0x000820, 0x031060, 0x010040,
-	0x001924, 0x2A0086, 0x00008D, 0x000464,
-	0x009D04, 0x291086, 0x180102, 0x000575,
-	0x010042, 0x28040A, 0x00018D, 0x000924,
-	0x280D02, 0x00000D, 0x000924, 0x281502,
-	0x10000D, 0x000820, 0x0002F5, 0x010040,
-	0x200007, 0x001175, 0x0002FD, 0x018042,
-	0x08000A, 0x000904, 0x24FA86, 0x000007,
-	0x000100, 0x080B20, 0x130B60, 0x1B0B60,
-	0x030A60, 0x010040, 0x050042, 0x3D004A,
-	0x35004A, 0x2D004A, 0x20000A, 0x0006F5,
-	0x010042, 0x28140A, 0x0004F5, 0x010042,
-	0x08000A, 0x000315, 0x010D04, 0x260286,
-	0x004015, 0x000095, 0x010D04, 0x25F086,
-	0x100022, 0x10002A, 0x261A06, 0x000007,
-	0x333104, 0x2AA904, 0x000007, 0x032124,
-	0x280502, 0x284402, 0x001124, 0x400102,
-	0x000424, 0x000424, 0x003224, 0x00292C,
-	0x00636C, 0x277386, 0x000007, 0x02B164,
-	0x000464, 0x000464, 0x00008D, 0x000A64,
-	0x280D02, 0x10008D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x00008D, 0x38B904,
-	0x000007, 0x03296C, 0x30010A, 0x0002F5,
-	0x010042, 0x08000A, 0x000904, 0x270286,
-	0x000007, 0x00212C, 0x28050A, 0x00316C,
-	0x00046C, 0x00046C, 0x28450A, 0x001124,
-	0x006B64, 0x100102, 0x00008D, 0x01096C,
-	0x280D0A, 0x10010D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x004124, 0x000424,
-	0x000424, 0x003224, 0x300102, 0x032944,
-	0x27FA86, 0x000007, 0x300002, 0x0004F5,
-	0x010042, 0x08000A, 0x000315, 0x010D04,
-	0x284086, 0x003124, 0x000464, 0x300102,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x284A86, 0x000007, 0x284402, 0x003124,
-	0x300502, 0x003924, 0x300583, 0x000883,
-	0x0005F5, 0x010042, 0x28040A, 0x00008D,
-	0x008124, 0x280D02, 0x00008D, 0x008124,
-	0x281502, 0x10018D, 0x000820, 0x0002F5,
-	0x010040, 0x220007, 0x001025, 0x000575,
-	0x030042, 0x09004A, 0x10000A, 0x0A0904,
-	0x121104, 0x000007, 0x001020, 0x050860,
-	0x050040, 0x0006FD, 0x018042, 0x09004A,
-	0x10000A, 0x0000A5, 0x0A0904, 0x121104,
-	0x000007, 0x000820, 0x019060, 0x010040,
-	0x0002F5, 0x010042, 0x08000A, 0x000904,
-	0x29CA86, 0x000007, 0x244206, 0x000007,
-	0x000606, 0x000007, 0x0002F5, 0x010042,
-	0x08000A, 0x000904, 0x2A1A86, 0x000007,
-	0x000100, 0x080B20, 0x138B60, 0x1B8B60,
-	0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60,
-	0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60,
-	0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60,
-	0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60,
-	0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60,
-	0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
-	0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60,
-	0x038A60, 0x000606, 0x018040, 0x00008D,
-	0x000A64, 0x280D02, 0x000A24, 0x00027D,
-	0x018042, 0x10000A, 0x001224, 0x0003FD,
-	0x018042, 0x08000A, 0x000904, 0x2C0A86,
-	0x000007, 0x00018D, 0x000A24, 0x000464,
-	0x000464, 0x080102, 0x000924, 0x000424,
-	0x000424, 0x100102, 0x02000D, 0x009144,
-	0x2C6186, 0x000007, 0x0001FD, 0x018042,
-	0x08000A, 0x000A44, 0x2C4386, 0x018042,
-	0x0A000D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00027D, 0x001020, 0x000606,
-	0x018040, 0x0002F5, 0x010042, 0x08000A,
-	0x000904, 0x2CB286, 0x000007, 0x00037D,
-	0x018042, 0x08000A, 0x000904, 0x2CE286,
-	0x000007, 0x000075, 0x002E7D, 0x010042,
-	0x0B804A, 0x000020, 0x000904, 0x000686,
-	0x010040, 0x31844A, 0x30048B, 0x000883,
-	0x00008D, 0x000810, 0x28143A, 0x00008D,
-	0x000810, 0x280C3A, 0x000675, 0x010042,
-	0x08000A, 0x003815, 0x010924, 0x280502,
-	0x0B000D, 0x000820, 0x0002F5, 0x010040,
-	0x000606, 0x220007, 0x000464, 0x000464,
-	0x000606, 0x000007, 0x000134, 0x007F8D,
-	0x00093C, 0x281D12, 0x282512, 0x001F32,
-	0x0E0007, 0x00010D, 0x00037D, 0x000820,
-	0x018040, 0x05D2F4, 0x000007, 0x080007,
-	0x00037D, 0x018042, 0x08000A, 0x000904,
-	0x2E8A86, 0x000007, 0x000606, 0x000007,
-	0x000007, 0x000012, 0x100007, 0x320007,
-	0x600007, 0x460007, 0x100080, 0x48001A,
-	0x004904, 0x2EF186, 0x000007, 0x001210,
-	0x58003A, 0x000145, 0x5C5D04, 0x000007,
-	0x000080, 0x48001A, 0x004904, 0x2F4186,
-	0x000007, 0x001210, 0x50003A, 0x005904,
-	0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5,
-	0x7FFF7D, 0x07D524, 0x004224, 0x500102,
-	0x200502, 0x000082, 0x40001A, 0x004104,
-	0x2FC986, 0x000007, 0x003865, 0x40001A,
-	0x004020, 0x00104D, 0x04C184, 0x31AB86,
-	0x000040, 0x040007, 0x000165, 0x000145,
-	0x004020, 0x000040, 0x000765, 0x080080,
-	0x40001A, 0x004104, 0x305986, 0x000007,
-	0x001210, 0x40003A, 0x004104, 0x30B286,
-	0x00004D, 0x0000CD, 0x004810, 0x20043A,
-	0x000882, 0x40001A, 0x004104, 0x30C186,
-	0x000007, 0x004820, 0x005904, 0x319886,
-	0x000040, 0x0007E5, 0x200480, 0x2816A0,
-	0x3216E0, 0x3A16E0, 0x4216E0, 0x021260,
-	0x000040, 0x000032, 0x400075, 0x00007D,
-	0x07D574, 0x200512, 0x000082, 0x40001A,
-	0x004104, 0x317186, 0x000007, 0x038A06,
-	0x640007, 0x0000E5, 0x000020, 0x000040,
-	0x000A65, 0x000020, 0x020040, 0x020040,
-	0x000040, 0x000165, 0x000042, 0x70000A,
-	0x007104, 0x323286, 0x000007, 0x060007,
-	0x019A06, 0x640007, 0x050000, 0x007020,
-	0x000040, 0x038A06, 0x640007, 0x000007,
-	0x00306D, 0x028860, 0x029060, 0x08000A,
-	0x028860, 0x008040, 0x100012, 0x00100D,
-	0x009184, 0x32D186, 0x000E0D, 0x009184,
-	0x33E186, 0x000007, 0x300007, 0x001020,
-	0x003B6D, 0x008040, 0x000080, 0x08001A,
-	0x000904, 0x32F186, 0x000007, 0x001220,
-	0x000DED, 0x008040, 0x008042, 0x10000A,
-	0x40000D, 0x109544, 0x000007, 0x001020,
-	0x000DED, 0x008040, 0x008042, 0x20040A,
-	0x000082, 0x08001A, 0x000904, 0x338186,
-	0x000007, 0x003B6D, 0x008042, 0x08000A,
-	0x000E15, 0x010984, 0x342B86, 0x600007,
-	0x08001A, 0x000C15, 0x010984, 0x341386,
-	0x000020, 0x1A0007, 0x0002ED, 0x008040,
-	0x620007, 0x00306D, 0x028042, 0x0A804A,
-	0x000820, 0x0A804A, 0x000606, 0x10804A,
-	0x000007, 0x282512, 0x001F32, 0x05D2F4,
-	0x54D104, 0x00735C, 0x000786, 0x000007,
-	0x0C0007, 0x0A0007, 0x1C0007, 0x003465,
-	0x020040, 0x004820, 0x025060, 0x40000A,
-	0x024060, 0x000040, 0x454944, 0x000007,
-	0x004020, 0x003AE5, 0x000040, 0x0028E5,
-	0x000042, 0x48000A, 0x004904, 0x39F886,
-	0x002C65, 0x000042, 0x40000A, 0x0000D5,
-	0x454104, 0x000007, 0x000655, 0x054504,
-	0x368286, 0x0001D5, 0x054504, 0x368086,
-	0x002B65, 0x000042, 0x003AE5, 0x50004A,
-	0x40000A, 0x45C3D4, 0x000007, 0x454504,
-	0x000007, 0x0000CD, 0x444944, 0x000007,
-	0x454504, 0x000007, 0x00014D, 0x554944,
-	0x000007, 0x045144, 0x367986, 0x002C65,
-	0x000042, 0x48000A, 0x4CD104, 0x000007,
-	0x04C144, 0x368386, 0x000007, 0x160007,
-	0x002CE5, 0x040042, 0x40000A, 0x004020,
-	0x000040, 0x002965, 0x000042, 0x40000A,
-	0x004104, 0x36F086, 0x000007, 0x002402,
-	0x383206, 0x005C02, 0x0025E5, 0x000042,
-	0x40000A, 0x004274, 0x002AE5, 0x000042,
-	0x40000A, 0x004274, 0x500112, 0x0029E5,
-	0x000042, 0x40000A, 0x004234, 0x454104,
-	0x000007, 0x004020, 0x000040, 0x003EE5,
-	0x000020, 0x000040, 0x002DE5, 0x400152,
-	0x50000A, 0x045144, 0x37DA86, 0x0000C5,
-	0x003EE5, 0x004020, 0x000040, 0x002BE5,
-	0x000042, 0x40000A, 0x404254, 0x000007,
-	0x002AE5, 0x004020, 0x000040, 0x500132,
-	0x040134, 0x005674, 0x0029E5, 0x020042,
-	0x42000A, 0x000042, 0x50000A, 0x05417C,
-	0x0028E5, 0x000042, 0x48000A, 0x0000C5,
-	0x4CC144, 0x38A086, 0x0026E5, 0x0027E5,
-	0x020042, 0x40004A, 0x50000A, 0x00423C,
-	0x00567C, 0x0028E5, 0x004820, 0x000040,
-	0x281D12, 0x282512, 0x001F72, 0x002965,
-	0x000042, 0x40000A, 0x004104, 0x393A86,
-	0x0E0007, 0x160007, 0x1E0007, 0x003EE5,
-	0x000042, 0x40000A, 0x004104, 0x397886,
-	0x002D65, 0x000042, 0x28340A, 0x003465,
-	0x020042, 0x42004A, 0x004020, 0x4A004A,
-	0x50004A, 0x05D2F4, 0x54D104, 0x00735C,
-	0x39E186, 0x000007, 0x000606, 0x080007,
-	0x0C0007, 0x080007, 0x0A0007, 0x0001E5,
-	0x020045, 0x004020, 0x000060, 0x000365,
-	0x000040, 0x002E65, 0x001A20, 0x0A1A60,
-	0x000040, 0x003465, 0x020042, 0x42004A,
-	0x004020, 0x4A004A, 0x000606, 0x50004A,
-	0x0017FD, 0x018042, 0x08000A, 0x000904,
-	0x225A86, 0x000007, 0x00107D, 0x018042,
-	0x0011FD, 0x33804A, 0x19804A, 0x20000A,
-	0x000095, 0x2A1144, 0x01A144, 0x3B9086,
-	0x00040D, 0x00B184, 0x3B9186, 0x0018FD,
-	0x018042, 0x0010FD, 0x09804A, 0x38000A,
-	0x000095, 0x010924, 0x003A64, 0x3B8186,
-	0x000007, 0x003904, 0x3B9286, 0x000007,
-	0x3B9A06, 0x00000D, 0x00008D, 0x000820,
-	0x00387D, 0x018040, 0x700002, 0x00117D,
-	0x018042, 0x00197D, 0x29804A, 0x30000A,
-	0x380002, 0x003124, 0x000424, 0x000424,
-	0x002A24, 0x280502, 0x00068D, 0x000810,
-	0x28143A, 0x00750D, 0x00B124, 0x002264,
-	0x3D0386, 0x284402, 0x000810, 0x280C3A,
-	0x0B800D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00758D, 0x00B124, 0x100102,
-	0x012144, 0x3E4986, 0x001810, 0x10003A,
-	0x00387D, 0x018042, 0x08000A, 0x000904,
-	0x3E4886, 0x030000, 0x3E4A06, 0x0000BD,
-	0x00008D, 0x023164, 0x000A64, 0x280D02,
-	0x0B808D, 0x000820, 0x0002FD, 0x018040,
-	0x200007, 0x00387D, 0x018042, 0x08000A,
-	0x000904, 0x3E3286, 0x030000, 0x0002FD,
-	0x018042, 0x08000A, 0x000904, 0x3D8286,
-	0x000007, 0x002810, 0x28043A, 0x00750D,
-	0x030924, 0x002264, 0x280D02, 0x02316C,
-	0x28450A, 0x0B810D, 0x000820, 0x0002FD,
-	0x018040, 0x200007, 0x00008D, 0x000A24,
-	0x3E4A06, 0x100102, 0x001810, 0x10003A,
-	0x0000BD, 0x003810, 0x30043A, 0x00187D,
-	0x018042, 0x0018FD, 0x09804A, 0x20000A,
-	0x0000AD, 0x028924, 0x07212C, 0x001010,
-	0x300583, 0x300D8B, 0x3014BB, 0x301C83,
-	0x002083, 0x00137D, 0x038042, 0x33844A,
-	0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB,
-	0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083,
-	0x001E0D, 0x0005FD, 0x018042, 0x20000A,
-	0x020924, 0x00068D, 0x00A96C, 0x00009D,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x3F6A86, 0x000007, 0x280502, 0x280D0A,
-	0x284402, 0x001810, 0x28143A, 0x0C008D,
-	0x000820, 0x0002FD, 0x018040, 0x220007,
-	0x003904, 0x225886, 0x001E0D, 0x00057D,
-	0x018042, 0x20000A, 0x020924, 0x0000A5,
-	0x0002FD, 0x018042, 0x08000A, 0x000904,
-	0x402A86, 0x000007, 0x280502, 0x280C02,
-	0x002010, 0x28143A, 0x0C010D, 0x000820,
-	0x0002FD, 0x018040, 0x225A06, 0x220007,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000,
-	0x000000, 0x000000, 0x000000, 0x000000
-};
-
-#endif	//_HWMCODE_
diff --git a/sound/oss/yss225.c b/sound/oss/yss225.c
deleted file mode 100644
index e700400..0000000
--- a/sound/oss/yss225.c
+++ /dev/null
@@ -1,319 +0,0 @@
-#include <linux/init.h>
-
-unsigned char page_zero[] __initdata = {
-0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
-0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
-0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19,
-0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01,
-0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00,
-0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02,
-0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
-0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00,
-0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02,
-0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40,
-0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02,
-0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00,
-0x1d, 0x02, 0xdf
-};    
-
-unsigned char page_one[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
-0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
-0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
-0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00,
-0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7,
-0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
-0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00,
-0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
-0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00,
-0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02,
-0x60, 0x00, 0x1b
-};
-
-unsigned char page_two[] __initdata = {
-0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
-0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07,
-0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46,
-0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46,
-0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07,
-0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05,
-0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05,
-0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
-};
-
-unsigned char page_three[] __initdata = {
-0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
-0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
-0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
-0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40,
-0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00,
-0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
-};
-
-unsigned char page_four[] __initdata = {
-0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
-0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
-0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60,
-0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00,
-0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22,
-0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
-};
-
-unsigned char page_six[] __initdata = {
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
-0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
-0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
-0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00,
-0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24,
-0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00,
-0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00,
-0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a,
-0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d,
-0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50,
-0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00,
-0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17,
-0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66,
-0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c,
-0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00,
-0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c,
-0x80, 0x00, 0x7e, 0x80, 0x80
-};
-
-unsigned char page_seven[] __initdata = {
-0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
-0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
-0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
-0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f,
-0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38,
-0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06,
-0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b,
-0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06,
-0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55,
-0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14,
-0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93,
-0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x02, 0x00
-};
-
-unsigned char page_zero_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_one_v2[] __initdata = {
-0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_two_v2[] __initdata = {
-0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-unsigned char page_three_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-unsigned char page_four_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_seven_v2[] __initdata = {
-0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-unsigned char mod_v2[] __initdata = {
-0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
-0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
-0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
-0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20,
-0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3,
-0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff,
-0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16,
-0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff,
-0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31,
-0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00,
-0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44,
-0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00,
-0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
-0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00,
-0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72,
-0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0,
-0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85,
-0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00,
-0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0,
-0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00,
-0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3,
-0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00,
-0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
-0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00,
-0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02,
-0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03,
-0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
-0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
-};
-unsigned char coefficients[] __initdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
-0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
-0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
-0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00,
-0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47,
-0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07,
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00,
-0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01,
-0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43,
-0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07,
-0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02,
-0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44,
-0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07,
-0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40,
-0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a,
-0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56,
-0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07,
-0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda,
-0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05,
-0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79,
-0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07,
-0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52,
-0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03,
-0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a,
-0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06,
-0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3,
-0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20,
-0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c,
-0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06,
-0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48,
-0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
-0xba
-};
-unsigned char coefficients2[] __initdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
-0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
-0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
-0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
-0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
-};
-unsigned char coefficients3[] __initdata = { 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
-0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
-0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
-0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99,
-0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02,
-0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f,
-0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03,
-0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c,
-0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03,
-0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51,
-0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04,
-0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e,
-0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05,
-0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14,
-0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06,
-0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1,
-0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07,
-0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7,
-0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08,
-0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3,
-0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09,
-0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99,
-0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a,
-0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66,
-0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a,
-0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c,
-0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b,
-0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28,
-0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c,
-0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e,
-0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d,
-0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb,
-0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e,
-0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1,
-0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f,
-0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae,
-0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff
-};
-
diff --git a/sound/oss/yss225.h b/sound/oss/yss225.h
deleted file mode 100644
index 56d8b6b..0000000
--- a/sound/oss/yss225.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __yss255_h__
-#define __yss255_h__
-
-extern unsigned char page_zero[256];
-extern unsigned char page_one[256];
-extern unsigned char page_two[128];
-extern unsigned char page_three[128];
-extern unsigned char page_four[128];
-extern unsigned char page_six[192];
-extern unsigned char page_seven[256];
-extern unsigned char page_zero_v2[96];
-extern unsigned char page_one_v2[96];
-extern unsigned char page_two_v2[48];
-extern unsigned char page_three_v2[48];
-extern unsigned char page_four_v2[48];
-extern unsigned char page_seven_v2[96];
-extern unsigned char mod_v2[304];
-extern unsigned char coefficients[364];
-extern unsigned char coefficients2[56];
-extern unsigned char coefficients3[404];
-
-
-#endif /* __ys225_h__ */
-
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 0b0a016..5322c50 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -366,25 +366,6 @@
 EXPORT_SYMBOL(register_sound_dsp);
 
 /**
- *	register_sound_synth - register a synth device
- *	@fops: File operations for the driver
- *	@dev: Unit number to allocate
- *
- *	Allocate a synth device. Unit is the number of the synth device requested.
- *	Pass -1 to request the next free synth unit. On success the allocated
- *	number is returned, on failure a negative error code is returned.
- */
-
-
-int register_sound_synth(const struct file_operations *fops, int dev)
-{
-	return sound_insert_unit(&chains[9], fops, dev, 9, 137,
-				 "synth", S_IRUSR | S_IWUSR, NULL);
-}
-
-EXPORT_SYMBOL(register_sound_synth);
-
-/**
  *	unregister_sound_special - unregister a special sound device
  *	@unit: unit number to allocate
  *
@@ -449,21 +430,6 @@
 
 EXPORT_SYMBOL(unregister_sound_dsp);
 
-/**
- *	unregister_sound_synth - unregister a synth device
- *	@unit: unit number to allocate
- *
- *	Release a sound device that was allocated with register_sound_synth().
- *	The unit passed is the return value from the register function.
- */
-
-void unregister_sound_synth(int unit)
-{
-	return sound_remove_unit(&chains[9], unit);
-}
-
-EXPORT_SYMBOL(unregister_sound_synth);
-
 /*
  *	Now our file operations
  */